diff options
Diffstat (limited to 'WebCore/rendering')
101 files changed, 3123 insertions, 2565 deletions
diff --git a/WebCore/rendering/InlineBox.cpp b/WebCore/rendering/InlineBox.cpp index 2575fb7..213737c 100644 --- a/WebCore/rendering/InlineBox.cpp +++ b/WebCore/rendering/InlineBox.cpp @@ -102,7 +102,7 @@ int InlineBox::height() const const Font& font = renderer()->style(m_firstLine)->font(); int result = font.height(); if (parent()) - result += flowObject->borderTop() + flowObject->paddingTop() + flowObject->borderBottom() + flowObject->paddingBottom(); + result += flowObject->borderAndPaddingHeight(); return result; } diff --git a/WebCore/rendering/MediaControlElements.cpp b/WebCore/rendering/MediaControlElements.cpp index 569f214..16827f5 100644 --- a/WebCore/rendering/MediaControlElements.cpp +++ b/WebCore/rendering/MediaControlElements.cpp @@ -74,7 +74,7 @@ MediaControlShadowRootElement::MediaControlShadowRootElement(Document* document, renderer->setStyle(rootStyle.release()); setRenderer(renderer); setAttached(); - setInDocument(true); + setInDocument(); } void MediaControlShadowRootElement::updateStyle() @@ -92,7 +92,7 @@ MediaControlElement::MediaControlElement(Document* document, PseudoId pseudo, HT , m_mediaElement(mediaElement) , m_pseudoStyleId(pseudo) { - setInDocument(true); + setInDocument(); switch (pseudo) { case MEDIA_CONTROLS_CURRENT_TIME_DISPLAY: m_displayType = MediaCurrentTimeDisplay; @@ -318,7 +318,7 @@ MediaControlInputElement::MediaControlInputElement(Document* document, PseudoId , m_pseudoStyleId(pseudo) { setInputType(type); - setInDocument(true); + setInDocument(); switch (pseudo) { case MEDIA_CONTROLS_MUTE_BUTTON: diff --git a/WebCore/rendering/RenderApplet.cpp b/WebCore/rendering/RenderApplet.cpp index 062641e..7411c54 100644 --- a/WebCore/rendering/RenderApplet.cpp +++ b/WebCore/rendering/RenderApplet.cpp @@ -59,9 +59,9 @@ void RenderApplet::createWidgetIfNecessary() // use fixed widths/heights from the style system when we can, since the widget might // not have an accurate m_width/m_height. int contentWidth = style()->width().isFixed() ? style()->width().value() : - width() - borderLeft() - borderRight() - paddingLeft() - paddingRight(); + width() - borderAndPaddingWidth(); int contentHeight = style()->height().isFixed() ? style()->height().value() : - height() - borderTop() - borderBottom() - paddingTop() - paddingBottom(); + height() - borderAndPaddingHeight(); for (Node* child = element->firstChild(); child; child = child->nextSibling()) { if (child->hasTagName(paramTag)) { HTMLParamElement* p = static_cast<HTMLParamElement*>(child); diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp index 3f53456..cf4101b 100644 --- a/WebCore/rendering/RenderBlock.cpp +++ b/WebCore/rendering/RenderBlock.cpp @@ -589,10 +589,10 @@ bool RenderBlock::isSelfCollapsingBlock() const // (c) have border/padding, // (d) have a min-height // (e) have specified that one of our margins can't collapse using a CSS extension - if (height() > 0 || - isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 || - style()->minHeight().isPositive() || - style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE) + if (height() > 0 + || isTable() || borderAndPaddingHeight() + || style()->minHeight().isPositive() + || style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE) return false; bool hasAutoHeight = style()->height().isAuto(); @@ -4011,7 +4011,7 @@ void RenderBlock::calcPrefWidths() } int toAdd = 0; - toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight(); + toAdd = borderAndPaddingWidth(); if (hasOverflowClip() && style()->overflowY() == OSCROLL) toAdd += verticalScrollbarWidth(); diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp index bd82683..e38cf25 100644 --- a/WebCore/rendering/RenderBox.cpp +++ b/WebCore/rendering/RenderBox.cpp @@ -514,7 +514,7 @@ int RenderBox::overrideHeight() const int RenderBox::calcBorderBoxWidth(int width) const { - int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight(); + int bordersPlusPadding = borderAndPaddingWidth(); if (style()->boxSizing() == CONTENT_BOX) return width + bordersPlusPadding; return max(width, bordersPlusPadding); @@ -522,7 +522,7 @@ int RenderBox::calcBorderBoxWidth(int width) const int RenderBox::calcBorderBoxHeight(int height) const { - int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom(); + int bordersPlusPadding = borderAndPaddingHeight(); if (style()->boxSizing() == CONTENT_BOX) return height + bordersPlusPadding; return max(height, bordersPlusPadding); @@ -531,14 +531,14 @@ int RenderBox::calcBorderBoxHeight(int height) const int RenderBox::calcContentBoxWidth(int width) const { if (style()->boxSizing() == BORDER_BOX) - width -= (borderLeft() + borderRight() + paddingLeft() + paddingRight()); + width -= borderAndPaddingWidth(); return max(0, width); } int RenderBox::calcContentBoxHeight(int height) const { if (style()->boxSizing() == BORDER_BOX) - height -= (borderTop() + borderBottom() + paddingTop() + paddingBottom()); + height -= borderAndPaddingHeight(); return max(0, height); } @@ -635,34 +635,36 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) return; } - int w = width(); - int h = height(); + return paintBoxDecorationsWithSize(paintInfo, tx, ty, width(), height()); +} +void RenderBox::paintBoxDecorationsWithSize(PaintInfo& paintInfo, int tx, int ty, int width, int height) +{ // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat // balloon layout is an example of this). - borderFitAdjust(tx, w); + borderFitAdjust(tx, width); // 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(), Normal); + paintBoxShadow(paintInfo.context, tx, ty, width, height, 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. - bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, IntRect(tx, ty, w, h)); + bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, IntRect(tx, ty, width, height)); if (!themePainted) { // The <body> only paints its background if the root element has defined a background // 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(), tx, ty, w, h); + paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), tx, ty, width, height); if (style()->hasAppearance()) - theme()->paintDecorations(this, paintInfo, IntRect(tx, ty, w, h)); + theme()->paintDecorations(this, paintInfo, IntRect(tx, ty, width, height)); } - paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset); + paintBoxShadow(paintInfo.context, tx, ty, width, height, 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()) - paintBorder(paintInfo.context, tx, ty, w, h, style()); + if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, IntRect(tx, ty, width, height)))) && style()->hasBorder()) + paintBorder(paintInfo.context, tx, ty, width, height, style()); } void RenderBox::paintMask(PaintInfo& paintInfo, int tx, int ty) @@ -1318,8 +1320,12 @@ void RenderBox::calcWidth() if (treatAsReplaced) { #else if (treatAsReplaced) +<<<<<<< HEAD:WebCore/rendering/RenderBox.cpp #endif setWidth(max(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight(), minPrefWidth())); +======= + setWidth(max(w.value() + borderAndPaddingWidth(), minPrefWidth())); +>>>>>>> webkit.org at r58956:WebCore/rendering/RenderBox.cpp #ifdef ANDROID_LAYOUT // in SSR mode with replaced box, if the box width is wider than the container width, @@ -1337,7 +1343,7 @@ void RenderBox::calcWidth() // Width calculations if (treatAsReplaced) - setWidth(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight()); + setWidth(w.value() + borderAndPaddingWidth()); else { // Calculate Width setWidth(calcWidthUsing(Width, containerWidth)); @@ -1508,7 +1514,7 @@ void RenderBox::calcHeight() // grab our cached flexible height. if (hasOverrideSize() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL && parent()->isFlexingChildren()) - h = Length(overrideSize() - borderTop() - borderBottom() - paddingTop() - paddingBottom(), Fixed); + h = Length(overrideSize() - borderAndPaddingHeight(), Fixed); else if (treatAsReplaced) h = Length(calcReplacedHeight(), Fixed); else { @@ -1519,8 +1525,7 @@ void RenderBox::calcHeight() // Block children of horizontal flexible boxes fill the height of the box. if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL && parent()->isStretchingChildren()) { - h = Length(parentBox()->contentHeight() - marginTop() - marginBottom() - - borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed); + h = Length(parentBox()->contentHeight() - marginTop() - marginBottom() - borderAndPaddingHeight(), Fixed); checkMinMaxHeight = false; } @@ -1545,7 +1550,7 @@ void RenderBox::calcHeight() // The only times we don't check min/max height are when a fixed length has // been given as an override. Just use that. The value has already been adjusted // for box-sizing. - heightResult = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom(); + heightResult = h.value() + borderAndPaddingHeight(); } setHeight(heightResult); @@ -1564,9 +1569,7 @@ void RenderBox::calcHeight() if (isRoot()) setHeight(max(height(), visHeight - margins)); else { - int marginsBordersPadding = margins + parentBox()->marginTop() + parentBox()->marginBottom() - + parentBox()->borderTop() + parentBox()->borderBottom() - + parentBox()->paddingTop() + parentBox()->paddingBottom(); + int marginsBordersPadding = margins + parentBox()->marginTop() + parentBox()->marginBottom() + parentBox()->borderAndPaddingHeight(); setHeight(max(height(), visHeight - marginsBordersPadding)); } } @@ -1660,7 +1663,7 @@ int RenderBox::calcPercentageHeight(const Length& height) // It is necessary to use the border-box to match WinIE's broken // box model. This is essential for sizing inside // table cells using percentage heights. - result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom()); + result -= borderAndPaddingHeight(); result = max(0, result); } } @@ -1733,8 +1736,7 @@ int RenderBox::calcReplacedHeightUsing(Length height) const // Don't let table cells squeeze percent-height replaced elements // <http://bugs.webkit.org/show_bug.cgi?id=15359> availableHeight = max(availableHeight, intrinsicSize().height()); - return height.calcValue(availableHeight - (borderTop() + borderBottom() - + paddingTop() + paddingBottom())); + return height.calcValue(availableHeight - borderAndPaddingHeight()); } return calcContentBoxHeight(height.calcValue(availableHeight)); @@ -1761,7 +1763,7 @@ int RenderBox::availableHeightUsing(const Length& h) const // artificially. We're going to rely on this cell getting expanded to some new // height, and then when we lay out again we'll use the calculation below. if (isTableCell() && (h.isAuto() || h.isPercent())) - return overrideSize() - (borderLeft() + borderRight() + paddingLeft() + paddingRight()); + return overrideSize() - borderAndPaddingWidth(); if (h.isPercent()) return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight())); @@ -1878,7 +1880,7 @@ void RenderBox::calcAbsoluteHorizontal() // instead of the the container block's. TextDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction(); - const int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight(); + const int bordersPlusPadding = borderAndPaddingWidth(); const Length marginLeft = style()->marginLeft(); const Length marginRight = style()->marginRight(); Length left = style()->left(); @@ -2187,7 +2189,7 @@ void RenderBox::calcAbsoluteVertical() const int containerHeight = containingBlockHeightForPositioned(containerBlock); - const int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom(); + const int bordersPlusPadding = borderAndPaddingHeight(); const Length marginTop = style()->marginTop(); const Length marginBottom = style()->marginBottom(); Length top = style()->top(); @@ -2428,7 +2430,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced() // NOTE: This value of width is FINAL in that the min/max width calculations // are dealt with in calcReplacedWidth(). This means that the steps to produce // correct max/min in the non-replaced version, are not necessary. - setWidth(calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight()); + setWidth(calcReplacedWidth() + borderAndPaddingWidth()); const int availableSpace = containerWidth - width(); /*-----------------------------------------------------------------------*\ @@ -2601,7 +2603,7 @@ void RenderBox::calcAbsoluteVerticalReplaced() // NOTE: This value of height is FINAL in that the min/max height calculations // are dealt with in calcReplacedHeight(). This means that the steps to produce // correct max/min in the non-replaced version, are not necessary. - setHeight(calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom()); + setHeight(calcReplacedHeight() + borderAndPaddingHeight()); const int availableSpace = containerHeight - height(); /*-----------------------------------------------------------------------*\ @@ -2787,8 +2789,8 @@ VisiblePosition RenderBox::positionForPoint(const IntPoint& point) int yPos = point.y(); if (isTable() && node()) { - int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft(); - int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom(); + int right = contentWidth() + borderAndPaddingWidth(); + int bottom = contentHeight() + borderAndPaddingHeight(); if (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) { if (xPos <= right / 2) diff --git a/WebCore/rendering/RenderBox.h b/WebCore/rendering/RenderBox.h index 68bbd51..1c766aa 100644 --- a/WebCore/rendering/RenderBox.h +++ b/WebCore/rendering/RenderBox.h @@ -308,6 +308,7 @@ protected: void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject); void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0); + void paintBoxDecorationsWithSize(PaintInfo&, int tx, int ty, int width, int height); void paintMaskImages(const PaintInfo&, int tx, int ty, int width, int height); #if PLATFORM(MAC) diff --git a/WebCore/rendering/RenderBoxModelObject.h b/WebCore/rendering/RenderBoxModelObject.h index db7538d..a4cf54a 100644 --- a/WebCore/rendering/RenderBoxModelObject.h +++ b/WebCore/rendering/RenderBoxModelObject.h @@ -75,6 +75,9 @@ public: virtual int borderLeft() const { return style()->borderLeftWidth(); } virtual int borderRight() const { return style()->borderRightWidth(); } + int borderAndPaddingHeight() const { return borderTop() + borderBottom() + paddingTop() + paddingBottom(); } + int borderAndPaddingWidth() const { return borderLeft() + borderRight() + paddingLeft() + paddingRight(); } + virtual int marginTop() const = 0; virtual int marginBottom() const = 0; virtual int marginLeft() const = 0; diff --git a/WebCore/rendering/RenderDataGrid.cpp b/WebCore/rendering/RenderDataGrid.cpp index bdf723f..00cbd7c 100644 --- a/WebCore/rendering/RenderDataGrid.cpp +++ b/WebCore/rendering/RenderDataGrid.cpp @@ -111,7 +111,7 @@ void RenderDataGrid::calcPrefWidths() m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); } - int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight(); + int toAdd = borderAndPaddingWidth(); m_minPrefWidth += toAdd; m_maxPrefWidth += toAdd; diff --git a/WebCore/rendering/RenderFieldset.cpp b/WebCore/rendering/RenderFieldset.cpp index d8cbd00..306e111 100644 --- a/WebCore/rendering/RenderFieldset.cpp +++ b/WebCore/rendering/RenderFieldset.cpp @@ -59,7 +59,7 @@ void RenderFieldset::calcPrefWidths() if (legendMarginRight.isFixed()) legendMinWidth += legendMarginRight.value(); - m_minPrefWidth = max(m_minPrefWidth, legendMinWidth + paddingLeft() + paddingRight() + borderLeft() + borderRight()); + m_minPrefWidth = max(m_minPrefWidth, legendMinWidth + borderAndPaddingWidth()); } } diff --git a/WebCore/rendering/RenderFileUploadControl.cpp b/WebCore/rendering/RenderFileUploadControl.cpp index 6a5c1e0..fa2a998 100644 --- a/WebCore/rendering/RenderFileUploadControl.cpp +++ b/WebCore/rendering/RenderFileUploadControl.cpp @@ -152,7 +152,7 @@ void RenderFileUploadControl::updateFromElement() renderer->setStyle(buttonStyle.release()); renderer->updateFromElement(); m_button->setAttached(); - m_button->setInDocument(true); + m_button->setInDocument(); addChild(renderer); } @@ -285,7 +285,7 @@ void RenderFileUploadControl::calcPrefWidths() m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); } - int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight(); + int toAdd = borderAndPaddingWidth(); m_minPrefWidth += toAdd; m_maxPrefWidth += toAdd; diff --git a/WebCore/rendering/RenderFlexibleBox.cpp b/WebCore/rendering/RenderFlexibleBox.cpp index 6882097..d0222cb 100644 --- a/WebCore/rendering/RenderFlexibleBox.cpp +++ b/WebCore/rendering/RenderFlexibleBox.cpp @@ -195,7 +195,7 @@ void RenderFlexibleBox::calcPrefWidths() m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); } - int toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight(); + int toAdd = borderAndPaddingWidth(); if (hasOverflowClip() && style()->overflowY() == OSCROLL) toAdd += verticalScrollbarWidth(); @@ -1035,7 +1035,7 @@ int RenderFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsign if (isHorizontal()) { // FIXME: For now just handle fixed values. int maxW = INT_MAX; - int w = child->overrideWidth() - (child->borderLeft() + child->borderRight() + child->paddingLeft() + child->paddingRight()); + int w = child->overrideWidth() - child->borderAndPaddingWidth(); if (!child->style()->maxWidth().isUndefined() && child->style()->maxWidth().isFixed()) maxW = child->style()->maxWidth().value(); @@ -1049,7 +1049,7 @@ int RenderFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsign } else { // FIXME: For now just handle fixed values. int maxH = INT_MAX; - int h = child->overrideHeight() - (child->borderTop() + child->borderBottom() + child->paddingTop() + child->paddingBottom()); + int h = child->overrideHeight() - child->borderAndPaddingHeight(); if (!child->style()->maxHeight().isUndefined() && child->style()->maxHeight().isFixed()) maxH = child->style()->maxHeight().value(); @@ -1062,7 +1062,7 @@ int RenderFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsign // FIXME: For now just handle fixed values. if (isHorizontal()) { int minW = child->minPrefWidth(); - int w = child->overrideWidth() - (child->borderLeft() + child->borderRight() + child->paddingLeft() + child->paddingRight()); + int w = child->overrideWidth() - child->borderAndPaddingWidth(); if (child->style()->minWidth().isFixed()) minW = child->style()->minWidth().value(); else if (child->style()->minWidth().type() == Intrinsic) @@ -1075,7 +1075,7 @@ int RenderFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsign } else { if (child->style()->minHeight().isFixed()) { int minH = child->style()->minHeight().value(); - int h = child->overrideHeight() - (child->borderLeft() + child->borderRight() + child->paddingLeft() + child->paddingRight()); + int h = child->overrideHeight() - child->borderAndPaddingHeight(); int allowedShrinkage = min(0, minH - h); return allowedShrinkage; } diff --git a/WebCore/rendering/RenderIFrame.cpp b/WebCore/rendering/RenderIFrame.cpp index 5852468..90cac14 100644 --- a/WebCore/rendering/RenderIFrame.cpp +++ b/WebCore/rendering/RenderIFrame.cpp @@ -77,6 +77,8 @@ void RenderIFrame::calcHeight() if (isScrollable || !style()->height().isFixed()) { FrameView* view = static_cast<FrameView*>(widget()); + if (!view) + return; int border = borderTop() + borderBottom(); setHeight(max(height(), view->contentsHeight() + border)); } @@ -126,6 +128,8 @@ void RenderIFrame::calcWidth() if (isScrollable || !style()->width().isFixed()) { FrameView* view = static_cast<FrameView*>(widget()); + if (!view) + return; int border = borderLeft() + borderRight(); setWidth(max(width(), view->contentsWidth() + border)); } diff --git a/WebCore/rendering/RenderImage.cpp b/WebCore/rendering/RenderImage.cpp index a2052fe..73cf73c 100644 --- a/WebCore/rendering/RenderImage.cpp +++ b/WebCore/rendering/RenderImage.cpp @@ -679,11 +679,11 @@ void RenderImage::calcPrefWidths() { ASSERT(prefWidthsDirty()); - int paddingAndBorders = paddingLeft() + paddingRight() + borderLeft() + borderRight(); - m_maxPrefWidth = calcReplacedWidth(false) + paddingAndBorders; + int borderAndPadding = borderAndPaddingWidth(); + m_maxPrefWidth = calcReplacedWidth(false) + borderAndPadding; if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) - m_maxPrefWidth = min(m_maxPrefWidth, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? paddingAndBorders : 0)); + m_maxPrefWidth = min(m_maxPrefWidth, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : 0)); if (style()->width().isPercent() || style()->height().isPercent() || style()->maxWidth().isPercent() || style()->maxHeight().isPercent() || diff --git a/WebCore/rendering/RenderInline.cpp b/WebCore/rendering/RenderInline.cpp index 6d3f462..69e6eab 100644 --- a/WebCore/rendering/RenderInline.cpp +++ b/WebCore/rendering/RenderInline.cpp @@ -274,7 +274,7 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after // content gets properly destroyed. if (document()->usesBeforeAfterRules()) - inlineCurr->children()->updateBeforeAfterContent(this, AFTER); + inlineCurr->children()->updateBeforeAfterContent(inlineCurr, AFTER); // Now we need to take all of the children starting from the first child // *after* currChild and append them all to the clone. diff --git a/WebCore/rendering/RenderInline.h b/WebCore/rendering/RenderInline.h index 7fcb516..4084b6e 100644 --- a/WebCore/rendering/RenderInline.h +++ b/WebCore/rendering/RenderInline.h @@ -71,6 +71,8 @@ public: int verticalPositionFromCache(bool firstLine) const; void invalidateVerticalPosition() { m_verticalPosition = PositionUndefined; } + RenderInline* inlineContinuation() const; + private: virtual RenderObjectChildList* virtualChildren() { return children(); } virtual const RenderObjectChildList* virtualChildren() const { return children(); } @@ -126,7 +128,6 @@ private: virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const; - RenderInline* inlineContinuation() const; void setContinuation(RenderBoxModelObject* c) { m_continuation = c; } virtual void childBecameNonInline(RenderObject* child); diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp index 7994325..ea29087 100644 --- a/WebCore/rendering/RenderLayer.cpp +++ b/WebCore/rendering/RenderLayer.cpp @@ -47,6 +47,7 @@ #include "CSSPropertyNames.h" #include "CSSStyleDeclaration.h" #include "CSSStyleSelector.h" +#include "Chrome.h" #include "Document.h" #include "EventHandler.h" #include "EventNames.h" @@ -79,12 +80,12 @@ #include "ScrollbarTheme.h" #include "SelectionController.h" #include "TextStream.h" -#include "TransformationMatrix.h" #include "TransformState.h" +#include "TransformationMatrix.h" #include "TranslateTransformOperation.h" -#include <wtf/text/CString.h> #include <wtf/StdLibExtras.h> #include <wtf/UnusedParam.h> +#include <wtf/text/CString.h> #if USE(ACCELERATED_COMPOSITING) #include "RenderLayerBacking.h" @@ -1277,17 +1278,6 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) child->updateLayerPositions(0); -#if USE(ACCELERATED_COMPOSITING) - if (compositor()->inCompositingMode()) { - // Our stacking context is guaranteed to contain all of our descendants that may need - // repositioning, so update compositing layers from there. - if (RenderLayer* compositingAncestor = stackingContext()->enclosingCompositingLayer()) { - bool isUpdateRoot = true; - compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants, isUpdateRoot); - } - } -#endif - RenderView* view = renderer()->view(); // We should have a RenderView if we're trying to scroll. @@ -1302,6 +1292,21 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai view->updateWidgetPositions(); } +#if USE(ACCELERATED_COMPOSITING) + if (compositor()->inCompositingMode()) { + // Our stacking context is guaranteed to contain all of our descendants that may need + // repositioning, so update compositing layers from there. + if (RenderLayer* compositingAncestor = stackingContext()->enclosingCompositingLayer()) { + if (compositor()->compositingConsultsOverlap()) + compositor()->updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor); + else { + bool isUpdateRoot = true; + compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants, isUpdateRoot); + } + } + } +#endif + RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); IntRect rectForRepaint = renderer()->clippedOverflowRectForRepaint(repaintContainer); @@ -1334,7 +1339,7 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai } } -void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, const ScrollAlignment& alignX, const ScrollAlignment& alignY) +void RenderLayer::scrollRectToVisible(const IntRect& rect, bool scrollToAnchor, const ScrollAlignment& alignX, const ScrollAlignment& alignY) { RenderLayer* parentLayer = 0; IntRect newRect = rect; @@ -1399,9 +1404,17 @@ void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, IntRect viewRect = frameView->visibleContentRect(true); IntRect r = getRectToExpose(viewRect, rect, alignX, alignY); - // If this is the outermost view that RenderLayer needs to scroll, then we should scroll the view recursively - // Other apps, like Mail, rely on this feature. - frameView->scrollRectIntoViewRecursively(r); + frameView->setScrollPosition(r.location()); + + // This is the outermost view of a web page, so after scrolling this view we + // scroll its container by calling Page::scrollRectIntoView. + // This only has an effect on the Mac platform in applications + // that put web views into scrolling containers, such as Mac OS X Mail. + // The canAutoscroll function in EventHandler also knows about this. + if (Frame* frame = frameView->frame()) { + if (Page* page = frame->page()) + page->chrome()->scrollRectIntoView(rect); + } } } } @@ -1548,8 +1561,7 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset style->setProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false, ec); style->setProperty(CSSPropertyMarginRight, String::number(renderer->marginRight() / zoomFactor) + "px", false, ec); } - int baseWidth = renderer->width() - (isBoxSizingBorder ? 0 - : renderer->borderLeft() + renderer->paddingLeft() + renderer->borderRight() + renderer->paddingRight()); + int baseWidth = renderer->width() - (isBoxSizingBorder ? 0 : renderer->borderAndPaddingWidth()); baseWidth = baseWidth / zoomFactor; style->setProperty(CSSPropertyWidth, String::number(baseWidth + difference.width()) + "px", false, ec); } @@ -1560,8 +1572,7 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset style->setProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false, ec); style->setProperty(CSSPropertyMarginBottom, String::number(renderer->marginBottom() / zoomFactor) + "px", false, ec); } - int baseHeight = renderer->height() - (isBoxSizingBorder ? 0 - : renderer->borderTop() + renderer->paddingTop() + renderer->borderBottom() + renderer->paddingBottom()); + int baseHeight = renderer->height() - (isBoxSizingBorder ? 0 : renderer->borderAndPaddingHeight()); baseHeight = baseHeight / zoomFactor; style->setProperty(CSSPropertyHeight, String::number(baseHeight + difference.height()) + "px", false, ec); } @@ -3186,7 +3197,7 @@ void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestR // We are clearing the :active chain because the mouse has been released. for (RenderObject* curr = activeNode->renderer(); curr; curr = curr->parent()) { if (curr->node() && !curr->isText()) - curr->node()->setInActiveChain(false); + curr->node()->clearInActiveChain(); } doc->setActiveNode(0); } else { @@ -3196,7 +3207,7 @@ void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestR // will need to reference this chain. for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) { if (curr->node() && !curr->isText()) { - curr->node()->setInActiveChain(true); + curr->node()->setInActiveChain(); } } doc->setActiveNode(newActiveNode); diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp index b5f74c6..b857420 100644 --- a/WebCore/rendering/RenderLayerBacking.cpp +++ b/WebCore/rendering/RenderLayerBacking.cpp @@ -38,6 +38,7 @@ #include "GraphicsLayer.h" #include "HTMLCanvasElement.h" #include "HTMLElement.h" +#include "HTMLIFrameElement.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" #include "InspectorTimelineAgent.h" @@ -384,6 +385,24 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() m_graphicsLayer->setContentsRect(contentsBox()); m_graphicsLayer->setDrawsContent(containsPaintedContent()); + + // If this is an iframe parent, update the iframe content's box + RenderLayerCompositor* innerCompositor = innerRenderLayerCompositor(); + if (innerCompositor) + innerCompositor->setRootPlatformLayerClippingBox(contentsBox()); +} + +RenderLayerCompositor* RenderLayerBacking::innerRenderLayerCompositor() const +{ + if (renderer()->isRenderIFrame()) { + HTMLIFrameElement* element = static_cast<HTMLIFrameElement*>(renderer()->node()); + if (Document* contentDocument = element->contentDocument()) { + if (RenderView* view = contentDocument->renderView()) + return view->compositor(); + } + } + + return 0; } void RenderLayerBacking::updateInternalHierarchy() @@ -823,7 +842,11 @@ FloatPoint RenderLayerBacking::contentsToGraphicsLayerCoordinates(const Graphics bool RenderLayerBacking::paintingGoesToWindow() const { - return m_owningLayer->isRootLayer(); + if (!m_owningLayer->isRootLayer()) + return false; + + // Iframe root layers paint into backing store. + return !toRenderView(renderer())->document()->ownerElement(); } void RenderLayerBacking::setContentsNeedDisplay() diff --git a/WebCore/rendering/RenderLayerBacking.h b/WebCore/rendering/RenderLayerBacking.h index a6907e7..8e0ee23 100644 --- a/WebCore/rendering/RenderLayerBacking.h +++ b/WebCore/rendering/RenderLayerBacking.h @@ -124,6 +124,8 @@ public: IntRect contentsBox() const; + RenderLayerCompositor* innerRenderLayerCompositor() const; + private: void createGraphicsLayer(); void destroyGraphicsLayer(); diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp index 25d8eda..e96e375 100644 --- a/WebCore/rendering/RenderLayerCompositor.cpp +++ b/WebCore/rendering/RenderLayerCompositor.cpp @@ -37,6 +37,7 @@ #include "GraphicsLayer.h" #include "HitTestResult.h" #include "HTMLCanvasElement.h" +#include "HTMLIFrameElement.h" #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) #include "HTMLMediaElement.h" #include "HTMLNames.h" @@ -124,7 +125,12 @@ void RenderLayerCompositor::enableCompositingMode(bool enable /* = true */) else destroyRootPlatformLayer(); - m_renderView->compositingStateChanged(m_compositing); + if (shouldPropagateCompositingToIFrameParent()) { + if (Element* ownerElement = m_renderView->document()->ownerElement()) { + // Trigger a recalcStyle in the parent document, to update compositing in that document. + ownerElement->setNeedsStyleRecalc(SyntheticStyleChange); + } + } } } @@ -592,6 +598,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O childState.m_compositingAncestor = layer; if (overlapMap) addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds); + willBeComposited = true; } } } @@ -622,6 +629,8 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O } } + ASSERT(willBeComposited == needsToBeComposited(layer)); + // If we have a software transform, and we have layers under us, we need to also // 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. @@ -699,19 +708,6 @@ void RenderLayerCompositor::removeCompositedChildren(RenderLayer* layer) hostingLayer->removeAllChildren(); } -void RenderLayerCompositor::parentInRootLayer(RenderLayer* layer) -{ - ASSERT(layer->isComposited()); - - GraphicsLayer* layerAnchor = layer->backing()->childForSuperlayers(); - - if (layerAnchor->parent() != m_rootPlatformLayer) { - layerAnchor->removeFromParent(); - if (m_rootPlatformLayer) - m_rootPlatformLayer->addChild(layerAnchor); - } -} - #if ENABLE(VIDEO) bool RenderLayerCompositor::canAccelerateVideoRendering(RenderVideo* o) const { @@ -799,11 +795,30 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, cons } if (layerBacking) { - layerBacking->parentForSublayers()->setChildren(layerChildren); + if (shouldPropagateCompositingToIFrameParent() && layer->renderer()->isRenderIFrame()) { + // This is an iframe parent. Make it the parent of the iframe document's root + layerBacking->parentForSublayers()->removeAllChildren(); + + RenderLayerCompositor* innerCompositor = layerBacking->innerRenderLayerCompositor(); + if (innerCompositor) { + GraphicsLayer* innerRootLayer = innerCompositor->rootPlatformLayer(); + if (innerRootLayer) + layerBacking->parentForSublayers()->addChild(innerRootLayer); + } + } else + layerBacking->parentForSublayers()->setChildren(layerChildren); childLayersOfEnclosingLayer.append(layerBacking->childForSuperlayers()); } } +void RenderLayerCompositor::setRootPlatformLayerClippingBox(const IntRect& contentsBox) +{ + if (m_clippingLayer) { + m_clippingLayer->setPosition(FloatPoint(contentsBox.x(), contentsBox.y())); + m_clippingLayer->setSize(FloatSize(contentsBox.width(), contentsBox.height())); + } +} + // This just updates layer geometry without changing the hierarchy. void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer) { @@ -957,7 +972,7 @@ RenderLayer* RenderLayerCompositor::rootRenderLayer() const GraphicsLayer* RenderLayerCompositor::rootPlatformLayer() const { - return m_rootPlatformLayer.get(); + return m_clippingLayer ? m_clippingLayer.get() : m_rootPlatformLayer.get(); } void RenderLayerCompositor::didMoveOnscreen() @@ -965,13 +980,28 @@ void RenderLayerCompositor::didMoveOnscreen() if (!m_rootPlatformLayer) return; - Frame* frame = m_renderView->frameView()->frame(); - Page* page = frame ? frame->page() : 0; - if (!page) - return; + bool attached = false; + if (shouldPropagateCompositingToIFrameParent()) { + if (Element* ownerElement = m_renderView->document()->ownerElement()) { + RenderObject* renderer = ownerElement->renderer(); + if (renderer && renderer->isRenderIFrame()) { + // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration() + // for the iframe's renderer in the parent document. + ownerElement->setNeedsStyleRecalc(SyntheticStyleChange); + attached = true; + } + } + } + + if (!attached) { + Frame* frame = m_renderView->frameView()->frame(); + Page* page = frame ? frame->page() : 0; + if (!page) + return; - page->chrome()->client()->attachRootGraphicsLayer(frame, m_rootPlatformLayer.get()); - m_rootLayerAttached = true; + page->chrome()->client()->attachRootGraphicsLayer(frame, m_rootPlatformLayer.get()); + } + m_rootLayerAttached = true; } void RenderLayerCompositor::willMoveOffscreen() @@ -979,19 +1009,45 @@ void RenderLayerCompositor::willMoveOffscreen() if (!m_rootPlatformLayer || !m_rootLayerAttached) return; - Frame* frame = m_renderView->frameView()->frame(); - Page* page = frame ? frame->page() : 0; - if (!page) - return; + bool detached = false; + if (shouldPropagateCompositingToIFrameParent()) { + if (Element* ownerElement = m_renderView->document()->ownerElement()) { + RenderObject* renderer = ownerElement->renderer(); + if (renderer->isRenderIFrame()) { + // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration() + // for the iframe's renderer in the parent document. + ownerElement->setNeedsStyleRecalc(SyntheticStyleChange); + detached = true; + } + } + } + + if (!detached) { + Frame* frame = m_renderView->frameView()->frame(); + Page* page = frame ? frame->page() : 0; + if (!page) + return; - page->chrome()->client()->attachRootGraphicsLayer(frame, 0); + page->chrome()->client()->attachRootGraphicsLayer(frame, 0); + } m_rootLayerAttached = false; } void RenderLayerCompositor::updateRootLayerPosition() { - if (m_rootPlatformLayer) - m_rootPlatformLayer->setSize(FloatSize(m_renderView->rightLayoutOverflow(), m_renderView->bottomLayoutOverflow())); + if (m_rootPlatformLayer) { + // FIXME: Adjust the y position of the m_rootPlatformLayer if we are clipping by its top edge + // Eventually this will be taken care of by scrolling logic + // https://bugs.webkit.org/show_bug.cgi?id=38518 + float height = m_renderView->bottomLayoutOverflow(); + float yOffset = 0; + + if (m_clippingLayer && height > m_clippingLayer->size().height()) + yOffset = m_clippingLayer->size().height() - height; + + m_rootPlatformLayer->setPosition(FloatPoint(0, yOffset)); + m_rootPlatformLayer->setSize(FloatSize(m_renderView->rightLayoutOverflow(), height)); + } } void RenderLayerCompositor::didStartAcceleratedAnimation() @@ -1007,6 +1063,18 @@ bool RenderLayerCompositor::has3DContent() const return layerHas3DContent(rootRenderLayer()); } +bool RenderLayerCompositor::shouldPropagateCompositingToIFrameParent() +{ + // Parent document content needs to be able to render on top of a composited iframe, so correct behavior + // is to have the parent document become composited too. However, this can cause problems on platforms that + // use native views for frames (like Mac), so disable that behavior on those platforms for now. +#if !PLATFORM(MAC) + return true; +#else + return false; +#endif +} + bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const { if (!canBeComposited(layer)) @@ -1194,7 +1262,9 @@ bool RenderLayerCompositor::requiresCompositingForPlugin(RenderObject* renderer) bool RenderLayerCompositor::requiresCompositingForIFrame(RenderObject* renderer) const { - return renderer->isRenderIFrame() && toRenderIFrame(renderer)->requiresAcceleratedCompositing(); + return shouldPropagateCompositingToIFrameParent() + && renderer->isRenderIFrame() + && toRenderIFrame(renderer)->requiresAcceleratedCompositing(); } bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* renderer) const @@ -1226,13 +1296,31 @@ void RenderLayerCompositor::ensureRootPlatformLayer() m_rootPlatformLayer = GraphicsLayer::create(0); m_rootPlatformLayer->setSize(FloatSize(m_renderView->rightLayoutOverflow(), m_renderView->bottomLayoutOverflow())); - m_rootPlatformLayer->setPosition(FloatPoint(0, 0)); + m_rootPlatformLayer->setPosition(FloatPoint()); + // 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); + if (shouldPropagateCompositingToIFrameParent()) { + // Create a clipping layer if this is an iframe + if (Element* ownerElement = m_renderView->document()->ownerElement()) { + RenderObject* renderer = ownerElement->renderer(); + if (renderer && renderer->isRenderIFrame()) { + m_clippingLayer = GraphicsLayer::create(0); + m_clippingLayer->setGeometryOrientation(GraphicsLayer::compositingCoordinatesOrientation()); +#ifndef NDEBUG + m_clippingLayer->setName("iframe Clipping"); +#endif + m_clippingLayer->setMasksToBounds(true); + m_clippingLayer->setAnchorPoint(FloatPoint()); + m_clippingLayer->addChild(m_rootPlatformLayer.get()); + } + } + } + didMoveOnscreen(); } diff --git a/WebCore/rendering/RenderLayerCompositor.h b/WebCore/rendering/RenderLayerCompositor.h index 43b8a17..36f7c15 100644 --- a/WebCore/rendering/RenderLayerCompositor.h +++ b/WebCore/rendering/RenderLayerCompositor.h @@ -136,6 +136,12 @@ public: // 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. bool has3DContent() const; + + // Some platforms may wish to connect compositing layer trees between iframes and + // their parent document. + static bool shouldPropagateCompositingToIFrameParent(); + + void setRootPlatformLayerClippingBox(const IntRect& contentsBox); private: // Whether the given RL needs a compositing layer. @@ -168,8 +174,6 @@ private: void setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer); void removeCompositedChildren(RenderLayer*); - void parentInRootLayer(RenderLayer*); - bool layerHas3DContent(const RenderLayer*) const; void ensureRootPlatformLayer(); @@ -199,6 +203,9 @@ private: bool m_compositing; bool m_rootLayerAttached; bool m_compositingLayersNeedRebuild; + + // Enclosing clipping layer for iframe content + OwnPtr<GraphicsLayer> m_clippingLayer; #if PROFILE_LAYER_REBUILD int m_rootLayerUpdateCount; diff --git a/WebCore/rendering/RenderListBox.cpp b/WebCore/rendering/RenderListBox.cpp index 15c652c..68591d6 100644 --- a/WebCore/rendering/RenderListBox.cpp +++ b/WebCore/rendering/RenderListBox.cpp @@ -188,7 +188,7 @@ void RenderListBox::calcPrefWidths() m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); } - int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight(); + int toAdd = borderAndPaddingWidth(); m_minPrefWidth += toAdd; m_maxPrefWidth += toAdd; @@ -221,7 +221,7 @@ int RenderListBox::listHeight() const void RenderListBox::calcHeight() { - int toAdd = paddingTop() + paddingBottom() + borderTop() + borderBottom(); + int toAdd = borderAndPaddingHeight(); int itemHeight = RenderListBox::itemHeight(); setHeight(itemHeight * size() - rowSpacing + toAdd); diff --git a/WebCore/rendering/RenderMenuList.cpp b/WebCore/rendering/RenderMenuList.cpp index 518925a..e2c6fd5 100644 --- a/WebCore/rendering/RenderMenuList.cpp +++ b/WebCore/rendering/RenderMenuList.cpp @@ -262,7 +262,7 @@ void RenderMenuList::calcPrefWidths() m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); } - int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight(); + int toAdd = borderAndPaddingWidth(); m_minPrefWidth += toAdd; m_maxPrefWidth += toAdd; diff --git a/WebCore/rendering/RenderObject.cpp b/WebCore/rendering/RenderObject.cpp index d63997a..1c93ac4 100644 --- a/WebCore/rendering/RenderObject.cpp +++ b/WebCore/rendering/RenderObject.cpp @@ -69,7 +69,7 @@ #endif #if ENABLE(SVG) -#include "RenderSVGResource.h" +#include "RenderSVGResourceContainer.h" #include "SVGRenderSupport.h" #endif @@ -2494,19 +2494,19 @@ VisiblePosition RenderObject::createVisiblePosition(const Position& position) } #if ENABLE(SVG) -const SVGRenderBase* RenderObject::toSVGRenderBase() const +RenderSVGResourceContainer* RenderObject::toRenderSVGResourceContainer() { ASSERT_NOT_REACHED(); return 0; } -RenderSVGResource* RenderObject::toRenderSVGResource() +FloatRect RenderObject::objectBoundingBox() const { ASSERT_NOT_REACHED(); - return 0; + return FloatRect(); } -FloatRect RenderObject::objectBoundingBox() const +FloatRect RenderObject::strokeBoundingBox() const { ASSERT_NOT_REACHED(); return FloatRect(); diff --git a/WebCore/rendering/RenderObject.h b/WebCore/rendering/RenderObject.h index ae12758..9d8a306 100644 --- a/WebCore/rendering/RenderObject.h +++ b/WebCore/rendering/RenderObject.h @@ -54,8 +54,7 @@ class RenderTheme; class TransformState; class VisiblePosition; #if ENABLE(SVG) -class RenderSVGResource; -class SVGRenderBase; +class RenderSVGResourceContainer; #endif /* @@ -332,16 +331,16 @@ public: // to add SVG renderer methods to RenderObject with an ASSERT_NOT_REACHED() default implementation. virtual bool isSVGRoot() const { return false; } virtual bool isSVGContainer() const { return false; } + virtual bool isSVGGradientStop() const { return false; } virtual bool isSVGHiddenContainer() const { return false; } virtual bool isRenderPath() const { return false; } virtual bool isSVGText() const { return false; } virtual bool isSVGImage() const { return false; } virtual bool isSVGForeignObject() const { return false; } - virtual bool isSVGResource() const { return false; } + virtual bool isSVGResourceContainer() const { return false; } virtual bool isSVGShadowTreeRootContainer() const { return false; } - virtual const SVGRenderBase* toSVGRenderBase() const; - virtual RenderSVGResource* toRenderSVGResource(); + virtual RenderSVGResourceContainer* toRenderSVGResourceContainer(); // FIXME: Those belong into a SVG specific base-class for all renderers (see above) // Unfortunately we don't have such a class yet, because it's not possible for all renderers @@ -356,6 +355,7 @@ public: // objectBoundingBox is returned local coordinates. // The name objectBoundingBox is taken from the SVG 1.1 spec. virtual FloatRect objectBoundingBox() const; + virtual FloatRect strokeBoundingBox() const; // Returns the smallest rectangle enclosing all of the painted content // respecting clipping, masking, filters, opacity, stroke-width and markers diff --git a/WebCore/rendering/RenderPath.cpp b/WebCore/rendering/RenderPath.cpp index b1e2a8f..ccb9562 100644 --- a/WebCore/rendering/RenderPath.cpp +++ b/WebCore/rendering/RenderPath.cpp @@ -4,6 +4,7 @@ 2005, 2007 Eric Seidel <eric@webkit.org> 2009 Google, Inc. 2009 Dirk Schulze <krit@webkit.org> + Copyright (C) Research In Motion Limited 2010. 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,7 +35,6 @@ #include "RenderSVGResourceFilter.h" #include "RenderSVGResourceMarker.h" #include "StrokeStyleApplier.h" -#include "SVGPaintServer.h" #include "SVGRenderSupport.h" #include "SVGStyledTransformableElement.h" #include "SVGTransformList.h" @@ -65,7 +65,7 @@ private: RenderPath::RenderPath(SVGStyledTransformableElement* node) : RenderSVGModelObject(node) - , m_needsBoundariesUpdate(false) // default is false, as this is only used when a RenderSVGResource tells us that the boundaries need to be recached + , m_needsBoundariesUpdate(false) // default is false, the cached rects are empty from the beginning , m_needsPathUpdate(true) // default is true, so we grab a Path object once from SVGStyledTransformableElement , m_needsTransformUpdate(true) // default is true, so we grab a AffineTransform object once from SVGStyledTransformableElement { @@ -73,10 +73,10 @@ RenderPath::RenderPath(SVGStyledTransformableElement* node) bool RenderPath::fillContains(const FloatPoint& point, bool requiresFill) const { - if (m_path.isEmpty()) + if (!m_fillBoundingBox.contains(point)) return false; - if (requiresFill && !SVGPaintServer::fillPaintServer(style(), this)) + if (requiresFill && !RenderSVGResource::fillPaintingResource(this, style())) return false; return m_path.contains(point, style()->svgStyle()->fillRule()); @@ -84,87 +84,16 @@ bool RenderPath::fillContains(const FloatPoint& point, bool requiresFill) const bool RenderPath::strokeContains(const FloatPoint& point, bool requiresStroke) const { - if (m_path.isEmpty()) + if (!m_strokeAndMarkerBoundingBox.contains(point)) return false; - if (requiresStroke && !SVGPaintServer::strokePaintServer(style(), this)) + if (requiresStroke && !RenderSVGResource::strokePaintingResource(this, style())) return false; BoundingRectStrokeStyleApplier strokeStyle(this, style()); return m_path.strokeContains(&strokeStyle, point); } -FloatRect RenderPath::objectBoundingBox() const -{ - if (m_path.isEmpty()) - return FloatRect(); - - if (m_cachedLocalFillBBox.isEmpty()) - m_cachedLocalFillBBox = m_path.boundingRect(); - - return m_cachedLocalFillBBox; -} - -FloatRect RenderPath::strokeBoundingBox() const -{ - if (m_path.isEmpty()) - return FloatRect(); - - if (!m_cachedLocalStrokeBBox.isEmpty()) - return m_cachedLocalStrokeBBox; - - m_cachedLocalStrokeBBox = objectBoundingBox(); - if (style()->svgStyle()->hasStroke()) { - BoundingRectStrokeStyleApplier strokeStyle(this, style()); - m_cachedLocalStrokeBBox.unite(m_path.strokeBoundingRect(&strokeStyle)); - } - - return m_cachedLocalStrokeBBox; -} - -FloatRect RenderPath::markerBoundingBox() const -{ - if (m_path.isEmpty()) - return FloatRect(); - - if (m_cachedLocalMarkerBBox.isEmpty()) - calculateMarkerBoundsIfNeeded(); - - return m_cachedLocalMarkerBBox; -} - -FloatRect RenderPath::repaintRectInLocalCoordinates() const -{ - if (m_path.isEmpty()) - return FloatRect(); - - // If we already have a cached repaint rect, return that - if (!m_cachedLocalRepaintRect.isEmpty()) - return m_cachedLocalRepaintRect; - - // FIXME: We need to be careful here. We assume that there is no filter, - // clipper, marker or masker if the rects are empty. - FloatRect rect = filterBoundingBoxForRenderer(this); - if (!rect.isEmpty()) - m_cachedLocalRepaintRect = rect; - else { - m_cachedLocalRepaintRect = strokeBoundingBox(); - m_cachedLocalRepaintRect.unite(markerBoundingBox()); - } - - rect = clipperBoundingBoxForRenderer(this); - if (!rect.isEmpty()) - m_cachedLocalRepaintRect.intersect(rect); - - rect = maskerBoundingBoxForRenderer(this); - if (!rect.isEmpty()) - m_cachedLocalRepaintRect.intersect(rect); - - style()->svgStyle()->inflateForShadow(m_cachedLocalRepaintRect); - - return m_cachedLocalRepaintRect; -} - void RenderPath::layout() { LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout()); @@ -173,15 +102,11 @@ void RenderPath::layout() // We need to update the Path object whenever the underlying SVGStyledTransformableElement uses relative values // as the viewport size may have changed. It would be nice to optimize this to detect these changes, and only // update when needed, even when using relative values. - if (!m_needsPathUpdate && element->hasRelativeValues()) - m_needsPathUpdate = true; - - bool needsUpdate = m_needsPathUpdate || m_needsTransformUpdate || m_needsBoundariesUpdate; + bool needsPathUpdate = m_needsPathUpdate; + if (!needsPathUpdate && element->hasRelativeValues()) + needsPathUpdate = true; - if (m_needsBoundariesUpdate) - m_needsBoundariesUpdate = false; - - if (m_needsPathUpdate) { + if (needsPathUpdate) { m_path = element->toPathData(); m_needsPathUpdate = false; } @@ -191,27 +116,31 @@ void RenderPath::layout() m_needsTransformUpdate = false; } - if (needsUpdate) - invalidateCachedBoundaries(); + // At this point LayoutRepainter already grabbed the old bounds, + // recalculate them now so repaintAfterLayout() uses the new bounds + if (needsPathUpdate || m_needsBoundariesUpdate) { + updateCachedBoundaries(); + m_needsBoundariesUpdate = false; + } repainter.repaintAfterLayout(); setNeedsLayout(false); } -static inline void fillAndStrokePath(const Path& path, GraphicsContext* context, RenderStyle* style, RenderPath* object) +static inline void fillAndStrokePath(const Path& path, GraphicsContext* context, RenderPath* object) { context->beginPath(); - SVGPaintServer* fillPaintServer = SVGPaintServer::fillPaintServer(style, object); - if (fillPaintServer) { + if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(object, object->style())) { context->addPath(path); - fillPaintServer->draw(context, object, ApplyToFillTargetType); + if (fillPaintingResource->applyResource(object, object->style(), context, ApplyToFillMode)) + fillPaintingResource->postApplyResource(object, context, ApplyToFillMode); } - - SVGPaintServer* strokePaintServer = SVGPaintServer::strokePaintServer(style, object); - if (strokePaintServer) { - context->addPath(path); // path is cleared when filled. - strokePaintServer->draw(context, object, ApplyToStrokeTargetType); + + if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(object, object->style())) { + context->addPath(path); + if (strokePaintingResource->applyResource(object, object->style(), context, ApplyToStrokeMode)) + strokePaintingResource->postApplyResource(object, context, ApplyToStrokeMode); } } @@ -222,10 +151,7 @@ void RenderPath::paint(PaintInfo& paintInfo, int, int) FloatRect boundingBox = repaintRectInLocalCoordinates(); FloatRect nonLocalBoundingBox = m_localTransform.mapRect(boundingBox); - // FIXME: The empty rect check is to deal with incorrect initial clip in renderSubtreeToImage - // unfortunately fixing that problem is fairly complex unless we were willing to just futz the - // rect to something "close enough" - if (!nonLocalBoundingBox.intersects(paintInfo.rect) && !paintInfo.rect.isEmpty()) + if (!nonLocalBoundingBox.intersects(paintInfo.rect)) return; PaintInfo childPaintInfo(paintInfo); @@ -239,13 +165,16 @@ void RenderPath::paint(PaintInfo& paintInfo, int, int) PaintInfo savedInfo(childPaintInfo); if (prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter)) { - if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES) + const SVGRenderStyle* svgStyle = style()->svgStyle(); + if (svgStyle->shapeRendering() == SR_CRISPEDGES) childPaintInfo.context->setShouldAntialias(false); - fillAndStrokePath(m_path, childPaintInfo.context, style(), this); - if (static_cast<SVGStyledElement*>(node())->supportsMarkers()) + fillAndStrokePath(m_path, childPaintInfo.context, this); + + if (svgStyle->hasMarkers()) m_markerLayoutInfo.drawMarkers(childPaintInfo); } + finishRenderSVGContent(this, childPaintInfo, filter, savedInfo.context); } @@ -288,20 +217,22 @@ bool RenderPath::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result, return false; } -void RenderPath::calculateMarkerBoundsIfNeeded() const +FloatRect RenderPath::calculateMarkerBoundsIfNeeded() { Document* doc = document(); SVGElement* svgElement = static_cast<SVGElement*>(node()); ASSERT(svgElement && svgElement->document()); if (!svgElement->isStyled()) - return; + return FloatRect(); SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement); if (!styledElement->supportsMarkers()) - return; + return FloatRect(); const SVGRenderStyle* svgStyle = style()->svgStyle(); + ASSERT(svgStyle->hasMarkers()); + AtomicString startMarkerId(svgStyle->markerStartResource()); AtomicString midMarkerId(svgStyle->markerMidResource()); AtomicString endMarkerId(svgStyle->markerEndResource()); @@ -326,24 +257,63 @@ void RenderPath::calculateMarkerBoundsIfNeeded() const endMarker->addClient(this); if (!startMarker && !midMarker && !endMarker) - return; + return FloatRect(); float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, svgStyle->strokeWidth(), 1.0f); - m_cachedLocalMarkerBBox = m_markerLayoutInfo.calculateBoundaries(startMarker, midMarker, endMarker, strokeWidth, m_path); + return m_markerLayoutInfo.calculateBoundaries(startMarker, midMarker, endMarker, strokeWidth, m_path); } -void RenderPath::invalidateCachedBoundaries() +void RenderPath::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) { - m_cachedLocalRepaintRect = FloatRect(); - m_cachedLocalStrokeBBox = FloatRect(); - m_cachedLocalFillBBox = FloatRect(); - m_cachedLocalMarkerBBox = FloatRect(); + setNeedsBoundariesUpdate(); + RenderSVGModelObject::styleWillChange(diff, newStyle); } -void RenderPath::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +void RenderPath::updateCachedBoundaries() { - invalidateCachedBoundaries(); - RenderSVGModelObject::styleWillChange(diff, newStyle); + if (m_path.isEmpty()) { + m_fillBoundingBox = FloatRect(); + m_strokeAndMarkerBoundingBox = FloatRect(); + m_repaintBoundingBox = FloatRect(); + return; + } + + // Cache _unclipped_ fill bounding box, used for calculations in resources + m_fillBoundingBox = m_path.boundingRect(); + + // Cache _unclipped_ stroke bounding box, used for calculations in resources (includes marker boundaries) + m_strokeAndMarkerBoundingBox = m_fillBoundingBox; + + const SVGRenderStyle* svgStyle = style()->svgStyle(); + if (svgStyle->hasStroke()) { + BoundingRectStrokeStyleApplier strokeStyle(this, style()); + m_strokeAndMarkerBoundingBox.unite(m_path.strokeBoundingRect(&strokeStyle)); + } + + if (svgStyle->hasMarkers()) { + FloatRect markerBounds = calculateMarkerBoundsIfNeeded(); + if (!markerBounds.isEmpty()) + m_strokeAndMarkerBoundingBox.unite(markerBounds); + } + + // Cache smallest possible repaint rectangle + + // FIXME: We need to be careful here. We assume that there is no resource, if the rect is empty. + FloatRect rect = filterBoundingBoxForRenderer(this); + if (rect.isEmpty()) + m_repaintBoundingBox = m_strokeAndMarkerBoundingBox; + else + m_repaintBoundingBox = rect; + + rect = clipperBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + m_repaintBoundingBox.intersect(rect); + + rect = maskerBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + m_repaintBoundingBox.intersect(rect); + + svgStyle->inflateForShadow(m_repaintBoundingBox); } } diff --git a/WebCore/rendering/RenderPath.h b/WebCore/rendering/RenderPath.h index ea4de40..5509057 100644 --- a/WebCore/rendering/RenderPath.h +++ b/WebCore/rendering/RenderPath.h @@ -50,11 +50,9 @@ private: bool fillContains(const FloatPoint&, bool requiresFill = true) const; bool strokeContains(const FloatPoint&, bool requiresStroke = true) const; - virtual FloatRect objectBoundingBox() const; - virtual FloatRect strokeBoundingBox() const; - virtual FloatRect markerBoundingBox() const; - virtual FloatRect repaintRectInLocalCoordinates() const; - + virtual FloatRect objectBoundingBox() const { return m_fillBoundingBox; } + virtual FloatRect strokeBoundingBox() const { return m_strokeAndMarkerBoundingBox; } + virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; } virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } virtual bool isRenderPath() const { return true; } @@ -67,8 +65,8 @@ private: virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); virtual void styleWillChange(StyleDifference, const RenderStyle*); - void calculateMarkerBoundsIfNeeded() const; - void invalidateCachedBoundaries(); + FloatRect calculateMarkerBoundsIfNeeded(); + void updateCachedBoundaries(); private: virtual AffineTransform localTransform() const { return m_localTransform; } @@ -78,11 +76,10 @@ private: bool m_needsTransformUpdate : 1; mutable Path m_path; - mutable FloatRect m_cachedLocalFillBBox; - mutable FloatRect m_cachedLocalStrokeBBox; - mutable FloatRect m_cachedLocalRepaintRect; - mutable FloatRect m_cachedLocalMarkerBBox; - mutable SVGMarkerLayoutInfo m_markerLayoutInfo; + FloatRect m_fillBoundingBox; + FloatRect m_strokeAndMarkerBoundingBox; + FloatRect m_repaintBoundingBox; + SVGMarkerLayoutInfo m_markerLayoutInfo; AffineTransform m_localTransform; }; diff --git a/WebCore/rendering/RenderProgress.cpp b/WebCore/rendering/RenderProgress.cpp index a9dbfe8..b42cc8b 100644 --- a/WebCore/rendering/RenderProgress.cpp +++ b/WebCore/rendering/RenderProgress.cpp @@ -23,9 +23,12 @@ #include "RenderProgress.h" +#include "HTMLDivElement.h" #include "HTMLProgressElement.h" #include "RenderTheme.h" +#include "RenderView.h" #include <wtf/CurrentTime.h> +#include <wtf/RefPtr.h> using namespace std; @@ -33,6 +36,23 @@ namespace WebCore { using namespace HTMLNames; +class ProgressValueElement : public HTMLDivElement { +public: + ProgressValueElement(Document*, Node* shadowParent); + +private: + virtual bool isShadowNode() const { return true; } + virtual Node* shadowParentNode() { return m_shadowParent; } + + Node* m_shadowParent; +}; + +ProgressValueElement::ProgressValueElement(Document* document, Node* shadowParent) +: HTMLDivElement(divTag, document) +, m_shadowParent(shadowParent) +{ +} + RenderProgress::RenderProgress(HTMLProgressElement* element) : RenderBlock(element) , m_position(-1) @@ -41,19 +61,48 @@ RenderProgress::RenderProgress(HTMLProgressElement* element) , m_animationDuration(0) , m_animating(false) , m_animationTimer(this, &RenderProgress::animationTimerFired) + , m_valuePart(0) { } +RenderProgress::~RenderProgress() +{ + if (m_valuePart) + m_valuePart->detach(); +} + void RenderProgress::layout() { ASSERT(needsLayout()); LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + IntSize oldSize = size(); + calcWidth(); calcHeight(); - - m_overflow.clear(); + if (m_valuePart) { + IntRect valuePartRect(borderLeft() + paddingLeft(), borderTop() + paddingTop(), lround((width() - borderLeft() - paddingLeft() - borderRight() - paddingRight()) * position()), height() - borderTop() - paddingTop() - borderBottom() - paddingBottom()); + if (style()->direction() == RTL) + valuePartRect.setX(width() - borderRight() - paddingRight() - valuePartRect.width()); + toRenderBox(m_valuePart->renderer())->setFrameRect(valuePartRect); + + if (oldSize != size()) + m_valuePart->renderer()->setChildNeedsLayout(true, false); + + LayoutStateMaintainer statePusher(view(), this, size()); + + IntRect oldRect = toRenderBox(m_valuePart->renderer())->frameRect(); + + m_valuePart->renderer()->layoutIfNeeded(); + + toRenderBox(m_valuePart->renderer())->setFrameRect(valuePartRect); + if (m_valuePart->renderer()->checkForRepaintDuringLayout()) + m_valuePart->renderer()->repaintDuringLayoutIfMoved(oldRect); + + statePusher.pop(); + addOverflowFromChild(toRenderBox(m_valuePart->renderer())); + } updateAnimationState(); @@ -62,6 +111,13 @@ void RenderProgress::layout() setNeedsLayout(false); } +void RenderProgress::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderBlock::styleDidChange(diff, oldStyle); + + updateValuePartState(); +} + void RenderProgress::updateFromElement() { HTMLProgressElement* element = progressElement(); @@ -71,9 +127,46 @@ void RenderProgress::updateFromElement() updateAnimationState(); + updateValuePartState(); + repaint(); } +void RenderProgress::updateValuePartState() +{ + bool needLayout = !style()->hasAppearance() || m_valuePart; + if (!style()->hasAppearance() && !m_valuePart) { + m_valuePart = new ProgressValueElement(document(), node()); + RefPtr<RenderStyle> styleForValuePart = createStyleForValuePart(style()); + m_valuePart->setRenderer(m_valuePart->createRenderer(renderArena(), styleForValuePart.get())); + m_valuePart->renderer()->setStyle(styleForValuePart.release()); + m_valuePart->setAttached(); + m_valuePart->setInDocument(); + addChild(m_valuePart->renderer()); + } else if (style()->hasAppearance() && m_valuePart) { + m_valuePart->detach(); + m_valuePart = 0; + } + if (needLayout) + setNeedsLayout(true); +} + +PassRefPtr<RenderStyle> RenderProgress::createStyleForValuePart(RenderStyle* parentStyle) +{ + RefPtr<RenderStyle> styleForValuePart; + RenderStyle* pseudoStyle = getCachedPseudoStyle(PROGRESS_BAR_VALUE); + if (pseudoStyle) + styleForValuePart = RenderStyle::clone(pseudoStyle); + else + styleForValuePart = RenderStyle::create(); + + if (parentStyle) + styleForValuePart->inheritFrom(parentStyle); + styleForValuePart->setDisplay(BLOCK); + styleForValuePart->setAppearance(ProgressBarValuePart); + return styleForValuePart.release(); +} + double RenderProgress::animationProgress() { return m_animating ? (fmod((currentTime() - m_animationStartTime), m_animationDuration) / m_animationDuration) : 0; @@ -99,7 +192,7 @@ void RenderProgress::updateAnimationState() m_animationDuration = theme()->animationDurationForProgressBar(this); m_animationRepeatInterval = theme()->animationRepeatIntervalForProgressBar(this); - bool animating = m_animationDuration > 0; + bool animating = style()->hasAppearance() && m_animationDuration > 0; if (animating == m_animating) return; diff --git a/WebCore/rendering/RenderProgress.h b/WebCore/rendering/RenderProgress.h index d6f5078..0d93ae7 100644 --- a/WebCore/rendering/RenderProgress.h +++ b/WebCore/rendering/RenderProgress.h @@ -27,10 +27,13 @@ namespace WebCore { class HTMLProgressElement; +class ProgressValueElement; class RenderProgress : public RenderBlock { public: RenderProgress(HTMLProgressElement*); + virtual ~RenderProgress(); + double position() { return m_position; } double animationProgress(); @@ -42,9 +45,12 @@ private: virtual void layout(); virtual void updateFromElement(); virtual void paint(PaintInfo&, int tx, int ty); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); void animationTimerFired(Timer<RenderProgress>*); void updateAnimationState(); + void updateValuePartState(); + PassRefPtr<RenderStyle> createStyleForValuePart(RenderStyle*); double m_position; double m_animationStartTime; @@ -52,6 +58,7 @@ private: double m_animationDuration; bool m_animating; Timer<RenderProgress> m_animationTimer; + RefPtr<ProgressValueElement> m_valuePart; }; inline RenderProgress* toRenderProgress(RenderObject* object) diff --git a/WebCore/rendering/RenderReplaced.cpp b/WebCore/rendering/RenderReplaced.cpp index 0ba99f5..d579b99 100644 --- a/WebCore/rendering/RenderReplaced.cpp +++ b/WebCore/rendering/RenderReplaced.cpp @@ -196,11 +196,11 @@ void RenderReplaced::calcPrefWidths() { ASSERT(prefWidthsDirty()); - int paddingAndBorders = paddingLeft() + paddingRight() + borderLeft() + borderRight(); - int width = calcReplacedWidth(false) + paddingAndBorders; + int borderAndPadding = borderAndPaddingWidth(); + int width = calcReplacedWidth(false) + borderAndPadding; if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) - width = min(width, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? paddingAndBorders : 0)); + width = min(width, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : 0)); if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent())) { m_minPrefWidth = 0; diff --git a/WebCore/rendering/RenderSVGBlock.h b/WebCore/rendering/RenderSVGBlock.h index 19cac62..a250c00 100644 --- a/WebCore/rendering/RenderSVGBlock.h +++ b/WebCore/rendering/RenderSVGBlock.h @@ -33,8 +33,6 @@ class RenderSVGBlock : public RenderBlock, protected SVGRenderBase { public: RenderSVGBlock(SVGElement*); - virtual const SVGRenderBase* toSVGRenderBase() const { return this; } - private: virtual void setStyle(PassRefPtr<RenderStyle>); virtual void updateBoxModelInfoFromStyle(); diff --git a/WebCore/rendering/RenderSVGGradientStop.cpp b/WebCore/rendering/RenderSVGGradientStop.cpp index 66391c8..754f31f 100644 --- a/WebCore/rendering/RenderSVGGradientStop.cpp +++ b/WebCore/rendering/RenderSVGGradientStop.cpp @@ -48,10 +48,8 @@ void RenderSVGGradientStop::styleDidChange(StyleDifference diff, const RenderSty // <stop> elements should only be allowed to make renderers under gradient elements // but I can imagine a few cases we might not be catching, so let's not crash if our parent isn't a gradient. - if (SVGGradientElement* gradient = gradientElement()) { - if (SVGResource* resource = gradient->canvasResource(this)) - resource->invalidate(); - } + if (SVGGradientElement* gradient = gradientElement()) + gradient->invalidateResourceClients(); } void RenderSVGGradientStop::layout() diff --git a/WebCore/rendering/RenderSVGGradientStop.h b/WebCore/rendering/RenderSVGGradientStop.h index 1d0858d..45da7b4 100644 --- a/WebCore/rendering/RenderSVGGradientStop.h +++ b/WebCore/rendering/RenderSVGGradientStop.h @@ -27,32 +27,40 @@ namespace WebCore { - class SVGGradientElement; - class SVGStopElement; - - // This class exists mostly so we can hear about gradient stop style changes - class RenderSVGGradientStop : public RenderObject { - public: - RenderSVGGradientStop(SVGStopElement*); - virtual ~RenderSVGGradientStop(); +class SVGGradientElement; +class SVGStopElement; + +// This class exists mostly so we can hear about gradient stop style changes +class RenderSVGGradientStop : public RenderObject { +public: + RenderSVGGradientStop(SVGStopElement*); + virtual ~RenderSVGGradientStop(); + + virtual bool isSVGGradientStop() const { return true; } + virtual const char* renderName() const { return "RenderSVGGradientStop"; } - virtual const char* renderName() const { return "RenderSVGGradientStop"; } + virtual void layout(); - virtual void layout(); + // This overrides are needed to prevent ASSERTs on <svg><stop /></svg> + // RenderObject's default implementations ASSERT_NOT_REACHED() + // https://bugs.webkit.org/show_bug.cgi?id=20400 + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject*) { return IntRect(); } + virtual FloatRect objectBoundingBox() const { return FloatRect(); } + virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); } - // This overrides are needed to prevent ASSERTs on <svg><stop /></svg> - // RenderObject's default implementations ASSERT_NOT_REACHED() - // https://bugs.webkit.org/show_bug.cgi?id=20400 - virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject*) { return IntRect(); } - virtual FloatRect objectBoundingBox() const { return FloatRect(); } - virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); } +protected: + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - protected: - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); +private: + SVGGradientElement* gradientElement() const; +}; + +inline const RenderSVGGradientStop* toRenderSVGGradientStop(const RenderObject* object) +{ + ASSERT(!object || object->isSVGGradientStop()); + return static_cast<const RenderSVGGradientStop*>(object); +} - private: - SVGGradientElement* gradientElement() const; - }; } #endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderSVGImage.h b/WebCore/rendering/RenderSVGImage.h index 120ac72..512892c 100644 --- a/WebCore/rendering/RenderSVGImage.h +++ b/WebCore/rendering/RenderSVGImage.h @@ -41,7 +41,6 @@ public: virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } private: - virtual const SVGRenderBase* toSVGRenderBase() const { return this; } virtual const char* renderName() const { return "RenderSVGImage"; } virtual bool isSVGImage() const { return true; } diff --git a/WebCore/rendering/RenderSVGInline.cpp b/WebCore/rendering/RenderSVGInline.cpp index 33459ce..85d148e 100644 --- a/WebCore/rendering/RenderSVGInline.cpp +++ b/WebCore/rendering/RenderSVGInline.cpp @@ -75,14 +75,10 @@ FloatRect RenderSVGInline::objectBoundingBox() const FloatRect RenderSVGInline::strokeBoundingBox() const { - const RenderObject* object = findTextRootObject(this); - ASSERT(object); - - const SVGRenderBase* renderer = object->toSVGRenderBase(); - if (!renderer) - return FloatRect(); + if (const RenderObject* object = findTextRootObject(this)) + return object->strokeBoundingBox(); - return renderer->strokeBoundingBox(); + return FloatRect(); } FloatRect RenderSVGInline::repaintRectInLocalCoordinates() const diff --git a/WebCore/rendering/RenderSVGInline.h b/WebCore/rendering/RenderSVGInline.h index e57b936..1afbb97 100644 --- a/WebCore/rendering/RenderSVGInline.h +++ b/WebCore/rendering/RenderSVGInline.h @@ -35,8 +35,6 @@ class RenderSVGInline : public RenderInline, protected SVGRenderBase { public: RenderSVGInline(Node*); - virtual const SVGRenderBase* toSVGRenderBase() const { return this; } - virtual const char* renderName() const { return "RenderSVGInline"; } virtual bool requiresLayer() const { return false; } diff --git a/WebCore/rendering/RenderSVGModelObject.h b/WebCore/rendering/RenderSVGModelObject.h index 760e79a..affa18d 100644 --- a/WebCore/rendering/RenderSVGModelObject.h +++ b/WebCore/rendering/RenderSVGModelObject.h @@ -49,8 +49,6 @@ class RenderSVGModelObject : public RenderObject, protected SVGRenderBase { public: RenderSVGModelObject(SVGStyledElement*); - virtual const SVGRenderBase* toSVGRenderBase() const { return this; } - virtual bool requiresLayer() const { return false; } virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); diff --git a/WebCore/rendering/RenderSVGResource.cpp b/WebCore/rendering/RenderSVGResource.cpp new file mode 100644 index 0000000..821e58a --- /dev/null +++ b/WebCore/rendering/RenderSVGResource.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * 2007 Rob Buis <buis@kde.org> + * 2008 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResource.h" + +#include "RenderSVGResourceContainer.h" +#include "RenderSVGResourceSolidColor.h" +#include "SVGURIReference.h" + +namespace WebCore { + +static inline void registerPendingResource(const AtomicString& id, const SVGPaint::SVGPaintType& paintType, const RenderObject* object) +{ + if (paintType != SVGPaint::SVG_PAINTTYPE_URI) + return; + + SVGElement* svgElement = static_cast<SVGElement*>(object->node()); + ASSERT(svgElement); + ASSERT(svgElement->isStyled()); + + object->document()->accessSVGExtensions()->addPendingResource(id, static_cast<SVGStyledElement*>(svgElement)); +} + +static inline void adjustColorForPseudoRules(const RenderStyle* style, bool useFillPaint, Color& color) +{ + if (style->insideLink() != InsideVisitedLink) + return; + + RenderStyle* visitedStyle = style->getCachedPseudoStyle(VISITED_LINK); + SVGPaint* visitedPaint = useFillPaint ? visitedStyle->svgStyle()->fillPaint() : visitedStyle->svgStyle()->strokePaint(); + if (visitedPaint->paintType() == SVGPaint::SVG_PAINTTYPE_URI) + return; + + Color visitedColor; + if (visitedPaint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) + visitedColor = visitedStyle->color(); + else + visitedColor = visitedPaint->color(); + + if (visitedColor.isValid()) + color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); +} + +// FIXME: This method and strokePaintingResource() should be refactored, to share even more code +RenderSVGResource* RenderSVGResource::fillPaintingResource(const RenderObject* object, const RenderStyle* style) +{ + ASSERT(object); + ASSERT(style); + + const SVGRenderStyle* svgStyle = style->svgStyle(); + if (!svgStyle || !svgStyle->hasFill()) + return 0; + + SVGPaint* fillPaint = svgStyle->fillPaint(); + ASSERT(fillPaint); + + RenderSVGResource* fillPaintingResource = 0; + + SVGPaint::SVGPaintType paintType = fillPaint->paintType(); + if (paintType == SVGPaint::SVG_PAINTTYPE_URI + || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) { + AtomicString id(SVGURIReference::getTarget(fillPaint->uri())); + fillPaintingResource = getRenderSVGResourceContainerById(object->document(), id); + + if (!fillPaintingResource) + registerPendingResource(id, paintType, object); + } + + if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !fillPaintingResource) { + RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource(); + fillPaintingResource = solidResource; + + Color fillColor; + if (fillPaint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) + fillColor = style->color(); + else + fillColor = fillPaint->color(); + + adjustColorForPseudoRules(style, true /* useFillPaint */, fillColor); + + // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT + if (fillColor.isValid()) + solidResource->setColor(fillColor); + else + fillPaintingResource = 0; + } + + if (!fillPaintingResource) { + // default value (black), see bug 11017 + RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource(); + solidResource->setColor(Color::black); + fillPaintingResource = solidResource; + } + + return fillPaintingResource; +} + +RenderSVGResource* RenderSVGResource::strokePaintingResource(const RenderObject* object, const RenderStyle* style) +{ + ASSERT(object); + ASSERT(style); + + const SVGRenderStyle* svgStyle = style->svgStyle(); + if (!svgStyle || !svgStyle->hasStroke()) + return 0; + + SVGPaint* strokePaint = svgStyle->strokePaint(); + ASSERT(strokePaint); + + RenderSVGResource* strokePaintingResource = 0; + FloatRect objectBoundingBox = object->objectBoundingBox(); + + SVGPaint::SVGPaintType paintType = strokePaint->paintType(); + if (!objectBoundingBox.isEmpty() + && (paintType == SVGPaint::SVG_PAINTTYPE_URI || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR)) { + AtomicString id(SVGURIReference::getTarget(strokePaint->uri())); + strokePaintingResource = getRenderSVGResourceContainerById(object->document(), id); + + if (!strokePaintingResource) + registerPendingResource(id, paintType, object); + } + + if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !strokePaintingResource) { + RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource(); + strokePaintingResource = solidResource; + + Color strokeColor; + if (strokePaint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) + strokeColor = style->color(); + else + strokeColor = strokePaint->color(); + + adjustColorForPseudoRules(style, false /* useFillPaint */, strokeColor); + + // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT + if (strokeColor.isValid()) + solidResource->setColor(strokeColor); + else + strokePaintingResource = 0; + } + + if (!strokePaintingResource) { + // default value (black), see bug 11017 + RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource(); + solidResource->setColor(Color::black); + strokePaintingResource = solidResource; + } + + return strokePaintingResource; +} + +RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource() +{ + static RenderSVGResourceSolidColor* s_sharedSolidPaintingResource = 0; + if (!s_sharedSolidPaintingResource) + s_sharedSolidPaintingResource = new RenderSVGResourceSolidColor; + return s_sharedSolidPaintingResource; +} + +void RenderSVGResource::markForLayoutAndResourceInvalidation(RenderObject* object) +{ + ASSERT(object); + ASSERT(object->node()); + ASSERT(object->node()->isSVGElement()); + + // Mark the renderer for layout + object->setNeedsLayout(true); + + // Notify any resources in the ancestor chain, that we've been invalidated + SVGElement* element = static_cast<SVGElement*>(object->node()); + if (!element->isStyled()) + return; + + static_cast<SVGStyledElement*>(element)->invalidateResourcesInAncestorChain(); +} + +} + +#endif diff --git a/WebCore/rendering/RenderSVGResource.h b/WebCore/rendering/RenderSVGResource.h index 1665404..f14fa4a 100644 --- a/WebCore/rendering/RenderSVGResource.h +++ b/WebCore/rendering/RenderSVGResource.h @@ -22,64 +22,47 @@ #define RenderSVGResource_h #if ENABLE(SVG) -#include "FloatRect.h" -#include "RenderSVGHiddenContainer.h" +#include "SVGDocumentExtensions.h" namespace WebCore { enum RenderSVGResourceType { MaskerResourceType, MarkerResourceType, + PatternResourceType, + LinearGradientResourceType, + RadialGradientResourceType, + SolidColorResourceType, FilterResourceType, ClipperResourceType }; -class RenderSVGResource : public RenderSVGHiddenContainer { -public: - RenderSVGResource(SVGStyledElement* node) - : RenderSVGHiddenContainer(node) - , m_id(node->getIDAttribute()) - { - ASSERT(node->document()); - node->document()->accessSVGExtensions()->addResource(m_id, this); - } - - virtual ~RenderSVGResource() - { - ASSERT(node()); - ASSERT(node()->document()); - node()->document()->accessSVGExtensions()->removeResource(m_id); - } - - void idChanged() - { - ASSERT(node()); - ASSERT(node()->document()); - SVGDocumentExtensions* extensions = node()->document()->accessSVGExtensions(); - - // Remove old id, that is guaranteed to be present in cache - extensions->removeResource(m_id); +enum RenderSVGResourceMode { + ApplyToDefaultMode = 1 << 0, // used for all resources except gradient/pattern + ApplyToFillMode = 1 << 1, + ApplyToStrokeMode = 1 << 2, + ApplyToTextMode = 1 << 3 // used in combination with ApplyTo{Fill|Stroke}Mode +}; - m_id = static_cast<Element*>(node())->getIDAttribute(); +class FloatRect; +class GraphicsContext; +class RenderObject; +class RenderStyle; +class RenderSVGResourceSolidColor; - // It's possible that an element is referencing us with the new id, and has to be notified that we're existing now - if (extensions->isPendingResource(m_id)) { - OwnPtr<HashSet<SVGStyledElement*> > clients(extensions->removePendingResource(m_id)); - if (clients->isEmpty()) - return; +class RenderSVGResource { +public: + RenderSVGResource() { } + virtual ~RenderSVGResource() { } - HashSet<SVGStyledElement*>::const_iterator it = clients->begin(); - const HashSet<SVGStyledElement*>::const_iterator end = clients->end(); + virtual void invalidateClients() = 0; + virtual void invalidateClient(RenderObject*) = 0; - for (; it != end; ++it) { - if (RenderObject* renderer = (*it)->renderer()) - renderer->setNeedsLayout(true); - } - } + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) = 0; + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short) { } + virtual FloatRect resourceBoundingBox(const FloatRect&) const = 0; - // Recache us with the new id - extensions->addResource(m_id, this); - } + virtual RenderSVGResourceType resourceType() const = 0; template<class Renderer> Renderer* cast() @@ -90,35 +73,15 @@ public: return 0; } - virtual RenderSVGResource* toRenderSVGResource() { return this; } - virtual bool isSVGResource() const { return true; } - virtual bool drawsContents() { return false; } - - virtual void invalidateClients() = 0; - virtual void invalidateClient(RenderObject*) = 0; - - virtual bool applyResource(RenderObject*, GraphicsContext*&) = 0; - virtual void postApplyResource(RenderObject*, GraphicsContext*&) { } - virtual FloatRect resourceBoundingBox(const FloatRect&) const = 0; - - virtual RenderSVGResourceType resourceType() const = 0; + // Helper utilities used in the render tree to access resources used for painting shapes/text (gradients & patterns only) + static RenderSVGResource* fillPaintingResource(const RenderObject*, const RenderStyle*); + static RenderSVGResource* strokePaintingResource(const RenderObject*, const RenderStyle*); + static RenderSVGResourceSolidColor* sharedSolidPaintingResource(); -private: - AtomicString m_id; +protected: + void markForLayoutAndResourceInvalidation(RenderObject*); }; -template<typename Renderer> -Renderer* getRenderSVGResourceById(Document* document, const AtomicString& id) -{ - if (id.isEmpty()) - return 0; - - if (RenderSVGResource* renderResource = document->accessSVGExtensions()->resourceById(id)) - return renderResource->cast<Renderer>(); - - return 0; -} - } #endif diff --git a/WebCore/rendering/RenderSVGResourceClipper.cpp b/WebCore/rendering/RenderSVGResourceClipper.cpp index ccb7397..2759976 100644 --- a/WebCore/rendering/RenderSVGResourceClipper.cpp +++ b/WebCore/rendering/RenderSVGResourceClipper.cpp @@ -38,13 +38,14 @@ #include "SVGStyledTransformableElement.h" #include "SVGUnitTypes.h" #include "SVGUseElement.h" +#include <wtf/UnusedParam.h> namespace WebCore { RenderSVGResourceType RenderSVGResourceClipper::s_resourceType = ClipperResourceType; -RenderSVGResourceClipper::RenderSVGResourceClipper(SVGStyledElement* node) - : RenderSVGResource(node) +RenderSVGResourceClipper::RenderSVGResourceClipper(SVGClipPathElement* node) + : RenderSVGResourceContainer(node) { } @@ -78,10 +79,18 @@ void RenderSVGResourceClipper::invalidateClient(RenderObject* object) return; delete m_clipper.take(object); + markForLayoutAndResourceInvalidation(object); } -bool RenderSVGResourceClipper::applyResource(RenderObject* object, GraphicsContext*& context) +bool RenderSVGResourceClipper::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) { + ASSERT(object); + ASSERT(context); +#ifndef NDEBUG + ASSERT(resourceMode == ApplyToDefaultMode); +#else + UNUSED_PARAM(resourceMode); +#endif applyClippingToContext(object, object->objectBoundingBox(), object->repaintRectInLocalCoordinates(), context); return true; } @@ -142,9 +151,6 @@ bool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext* context, const bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, const FloatRect& objectBoundingBox, const FloatRect& repaintRect, GraphicsContext* context) { - ASSERT(object); - ASSERT(context); - if (!m_clipper.contains(object)) m_clipper.set(object, new ClipperData); diff --git a/WebCore/rendering/RenderSVGResourceClipper.h b/WebCore/rendering/RenderSVGResourceClipper.h index 8de17d4..0b6f2b3 100644 --- a/WebCore/rendering/RenderSVGResourceClipper.h +++ b/WebCore/rendering/RenderSVGResourceClipper.h @@ -27,7 +27,7 @@ #include "ImageBuffer.h" #include "IntSize.h" #include "Path.h" -#include "RenderSVGResource.h" +#include "RenderSVGResourceContainer.h" #include "SVGClipPathElement.h" #include "SVGUnitTypes.h" @@ -40,10 +40,9 @@ struct ClipperData { OwnPtr<ImageBuffer> clipMaskImage; }; -class RenderSVGResourceClipper : public RenderSVGResource { - +class RenderSVGResourceClipper : public RenderSVGResourceContainer { public: - RenderSVGResourceClipper(SVGStyledElement*); + RenderSVGResourceClipper(SVGClipPathElement*); virtual ~RenderSVGResourceClipper(); virtual const char* renderName() const { return "RenderSVGResourceClipper"; } @@ -51,7 +50,7 @@ public: virtual void invalidateClients(); virtual void invalidateClient(RenderObject*); - virtual bool applyResource(RenderObject*, GraphicsContext*&); + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); virtual FloatRect resourceBoundingBox(const FloatRect&) const; virtual RenderSVGResourceType resourceType() const { return ClipperResourceType; } diff --git a/WebCore/rendering/RenderSVGResourceContainer.h b/WebCore/rendering/RenderSVGResourceContainer.h new file mode 100644 index 0000000..b63575d --- /dev/null +++ b/WebCore/rendering/RenderSVGResourceContainer.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) Research In Motion Limited 2010. 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 RenderSVGResourceContainer_h +#define RenderSVGResourceContainer_h + +#if ENABLE(SVG) +#include "RenderSVGHiddenContainer.h" +#include "RenderSVGResource.h" + +namespace WebCore { + +class RenderSVGResourceContainer : public RenderSVGHiddenContainer, + public RenderSVGResource { +public: + RenderSVGResourceContainer(SVGStyledElement* node) + : RenderSVGHiddenContainer(node) + , RenderSVGResource() + , m_id(node->getIDAttribute()) + { + ASSERT(node->document()); + node->document()->accessSVGExtensions()->addResource(m_id, this); + } + + virtual ~RenderSVGResourceContainer() + { + ASSERT(node()); + ASSERT(node()->document()); + node()->document()->accessSVGExtensions()->removeResource(m_id); + } + + void idChanged() + { + ASSERT(node()); + ASSERT(node()->document()); + SVGDocumentExtensions* extensions = node()->document()->accessSVGExtensions(); + + // Remove old id, that is guaranteed to be present in cache + extensions->removeResource(m_id); + + m_id = static_cast<Element*>(node())->getIDAttribute(); + + // It's possible that an element is referencing us with the new id, and has to be notified that we're existing now + if (extensions->isPendingResource(m_id)) { + OwnPtr<HashSet<SVGStyledElement*> > clients(extensions->removePendingResource(m_id)); + if (clients->isEmpty()) + return; + + HashSet<SVGStyledElement*>::const_iterator it = clients->begin(); + const HashSet<SVGStyledElement*>::const_iterator end = clients->end(); + + for (; it != end; ++it) { + if (RenderObject* renderer = (*it)->renderer()) + renderer->setNeedsLayout(true); + } + } + + // Recache us with the new id + extensions->addResource(m_id, this); + } + + virtual bool isSVGResourceContainer() const { return true; } + virtual bool drawsContents() { return false; } + + virtual RenderSVGResourceContainer* toRenderSVGResourceContainer() { return this; } + +private: + AtomicString m_id; +}; + +inline RenderSVGResourceContainer* getRenderSVGResourceContainerById(Document* document, const AtomicString& id) +{ + if (id.isEmpty()) + return 0; + + if (RenderSVGResourceContainer* renderResource = document->accessSVGExtensions()->resourceById(id)) + return renderResource; + + return 0; +} + +template<typename Renderer> +Renderer* getRenderSVGResourceById(Document* document, const AtomicString& id) +{ + if (RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id)) + return container->cast<Renderer>(); + + return 0; +} + +} + +#endif +#endif diff --git a/WebCore/rendering/RenderSVGResourceFilter.cpp b/WebCore/rendering/RenderSVGResourceFilter.cpp index cbedfe3..ac3ea49 100644 --- a/WebCore/rendering/RenderSVGResourceFilter.cpp +++ b/WebCore/rendering/RenderSVGResourceFilter.cpp @@ -43,6 +43,7 @@ #include "SVGStyledElement.h" #include "SVGUnitTypes.h" #include <wtf/Vector.h> +#include <wtf/UnusedParam.h> static const float kMaxFilterSize = 5000.0f; @@ -52,8 +53,8 @@ namespace WebCore { RenderSVGResourceType RenderSVGResourceFilter::s_resourceType = FilterResourceType; -RenderSVGResourceFilter::RenderSVGResourceFilter(SVGStyledElement* node) - : RenderSVGResource(node) +RenderSVGResourceFilter::RenderSVGResourceFilter(SVGFilterElement* node) + : RenderSVGResourceContainer(node) , m_savedContext(0) , m_sourceGraphicBuffer(0) { @@ -88,7 +89,8 @@ void RenderSVGResourceFilter::invalidateClient(RenderObject* object) if (!m_filter.contains(object)) return; - delete m_filter.take(object); + delete m_filter.take(object); + markForLayoutAndResourceInvalidation(object); } PassOwnPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives() @@ -134,10 +136,15 @@ bool RenderSVGResourceFilter::fitsInMaximumImageSize(const FloatSize& size, Floa return matchesFilterSize; } -bool RenderSVGResourceFilter::applyResource(RenderObject* object, GraphicsContext*& context) +bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(object); ASSERT(context); +#ifndef NDEBUG + ASSERT(resourceMode == ApplyToDefaultMode); +#else + UNUSED_PARAM(resourceMode); +#endif // Returning false here, to avoid drawings onto the context. We just want to // draw the stored filter output, not the unfiltered object as well. @@ -154,12 +161,7 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, GraphicsContex if (!filterData->builder) return false; - const SVGRenderBase* renderer = object->toSVGRenderBase(); - if (!renderer) - return false; - - FloatRect paintRect = renderer->strokeBoundingBox(); - paintRect.unite(renderer->markerBoundingBox()); + FloatRect paintRect = object->strokeBoundingBox(); // Calculate the scale factor for the use of filterRes. // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion @@ -228,10 +230,15 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, GraphicsContex return true; } -void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsContext*& context) +void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(object); ASSERT(context); +#ifndef NDEBUG + ASSERT(resourceMode == ApplyToDefaultMode); +#else + UNUSED_PARAM(resourceMode); +#endif if (!m_filter.contains(object)) return; diff --git a/WebCore/rendering/RenderSVGResourceFilter.h b/WebCore/rendering/RenderSVGResourceFilter.h index 2cd4b6c..ce4a7e1 100644 --- a/WebCore/rendering/RenderSVGResourceFilter.h +++ b/WebCore/rendering/RenderSVGResourceFilter.h @@ -28,7 +28,7 @@ #if ENABLE(SVG) && ENABLE(FILTERS) #include "FloatRect.h" #include "ImageBuffer.h" -#include "RenderSVGResource.h" +#include "RenderSVGResourceContainer.h" #include "SVGFilter.h" #include "SVGFilterBuilder.h" #include "SVGFilterElement.h" @@ -55,9 +55,9 @@ struct FilterData { class GraphicsContext; -class RenderSVGResourceFilter : public RenderSVGResource { +class RenderSVGResourceFilter : public RenderSVGResourceContainer { public: - RenderSVGResourceFilter(SVGStyledElement*); + RenderSVGResourceFilter(SVGFilterElement*); virtual ~RenderSVGResourceFilter(); virtual const char* renderName() const { return "RenderSVGResourceFilter"; } @@ -65,8 +65,8 @@ public: virtual void invalidateClients(); virtual void invalidateClient(RenderObject*); - virtual bool applyResource(RenderObject*, GraphicsContext*&); - virtual void postApplyResource(RenderObject*, GraphicsContext*&); + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode); virtual FloatRect resourceBoundingBox(const FloatRect&) const; diff --git a/WebCore/rendering/RenderSVGResourceGradient.cpp b/WebCore/rendering/RenderSVGResourceGradient.cpp new file mode 100644 index 0000000..6c9d784 --- /dev/null +++ b/WebCore/rendering/RenderSVGResourceGradient.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * 2008 Eric Seidel <eric@webkit.org> + * 2008 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceGradient.h" + +#include "GradientAttributes.h" +#include "GraphicsContext.h" +#include "SVGRenderSupport.h" +#include <wtf/UnusedParam.h> + +namespace WebCore { + +RenderSVGResourceGradient::RenderSVGResourceGradient(SVGGradientElement* node) + : RenderSVGResourceContainer(node) +#if PLATFORM(CG) + , m_savedContext(0) +#endif +{ +} + +RenderSVGResourceGradient::~RenderSVGResourceGradient() +{ + deleteAllValues(m_gradient); + m_gradient.clear(); +} + +void RenderSVGResourceGradient::invalidateClients() +{ + const HashMap<RenderObject*, GradientData*>::const_iterator end = m_gradient.end(); + for (HashMap<RenderObject*, GradientData*>::const_iterator it = m_gradient.begin(); it != end; ++it) + markForLayoutAndResourceInvalidation(it->first); + + deleteAllValues(m_gradient); + m_gradient.clear(); +} + +void RenderSVGResourceGradient::invalidateClient(RenderObject* object) +{ + ASSERT(object); + + // FIXME: The HashMap should always contain the object on calling invalidateClient. A race condition + // during the parsing can causes a call of invalidateClient right before the call of applyResource. + // We return earlier for the moment. This bug should be fixed in: + // https://bugs.webkit.org/show_bug.cgi?id=35181 + if (!m_gradient.contains(object)) + return; + + delete m_gradient.take(object); + markForLayoutAndResourceInvalidation(object); +} + +#if PLATFORM(CG) +static inline AffineTransform absoluteTransformForRenderer(const RenderObject* object) +{ + AffineTransform absoluteTransform; + + const RenderObject* currentObject = object; + while (currentObject) { + absoluteTransform = currentObject->localToParentTransform() * absoluteTransform; + currentObject = currentObject->parent(); + } + + return absoluteTransform; +} + +static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& context, + GraphicsContext*& savedContext, + OwnPtr<ImageBuffer>& imageBuffer, + const RenderObject* object) +{ + const RenderObject* textRootBlock = findTextRootObject(object); + + AffineTransform transform = absoluteTransformForRenderer(textRootBlock); + FloatRect maskAbsoluteBoundingBox = transform.mapRect(textRootBlock->repaintRectInLocalCoordinates()); + + IntRect maskImageRect = enclosingIntRect(maskAbsoluteBoundingBox); + if (maskImageRect.isEmpty()) + return false; + + // Allocate an image buffer as big as the absolute unclipped size of the object + OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskImageRect.size()); + if (!maskImage) + return false; + + GraphicsContext* maskImageContext = maskImage->context(); + + // Transform the mask image coordinate system to absolute screen coordinates + maskImageContext->translate(-maskAbsoluteBoundingBox.x(), -maskAbsoluteBoundingBox.y()); + maskImageContext->concatCTM(transform); + + imageBuffer.set(maskImage.release()); + savedContext = context; + context = maskImageContext; + + return true; +} + +static inline AffineTransform clipToTextMask(GraphicsContext* context, + OwnPtr<ImageBuffer>& imageBuffer, + const RenderObject* object, + GradientData* gradientData) +{ + const RenderObject* textRootBlock = findTextRootObject(object); + context->clipToImageBuffer(textRootBlock->repaintRectInLocalCoordinates(), imageBuffer.get()); + + AffineTransform matrix; + if (gradientData->boundingBoxMode) { + FloatRect maskBoundingBox = textRootBlock->objectBoundingBox(); + matrix.translate(maskBoundingBox.x(), maskBoundingBox.y()); + matrix.scaleNonUniform(maskBoundingBox.width(), maskBoundingBox.height()); + } + matrix.multiply(gradientData->transform); + return matrix; +} +#endif + +bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode) +{ + ASSERT(object); + ASSERT(style); + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + + // Be sure to synchronize all SVG properties on the gradientElement _before_ processing any further. + // Otherwhise the call to collectGradientAttributes() in createTileImage(), may cause the SVG DOM property + // synchronization to kick in, which causes invalidateClients() to be called, which in turn deletes our + // GradientData object! Leaving out the line below will cause svg/dynamic-updates/SVG*GradientElement-svgdom* to crash. + SVGGradientElement* gradientElement = static_cast<SVGGradientElement*>(node()); + if (!gradientElement) + return false; + + gradientElement->updateAnimatedSVGAttribute(anyQName()); + + if (!m_gradient.contains(object)) + m_gradient.set(object, new GradientData); + + GradientData* gradientData = m_gradient.get(object); + + // Create gradient object + if (!gradientData->gradient) + buildGradient(gradientData, gradientElement); + + if (!gradientData->gradient) + return false; + + // Draw gradient + context->save(); + + bool isPaintingText = resourceMode & ApplyToTextMode; + if (isPaintingText) { +#if PLATFORM(CG) + if (!createMaskAndSwapContextForTextGradient(context, m_savedContext, m_imageBuffer, object)) { + context->restore(); + return false; + } +#endif + + context->setTextDrawingMode(resourceMode & ApplyToFillMode ? cTextFill : cTextStroke); + } + + AffineTransform transform; + + // CG platforms will handle the gradient space transform for text after applying the + // resource, so don't apply it here. For non-CG platforms, we want the text bounding + // box applied to the gradient space transform now, so the gradient shader can use it. +#if PLATFORM(CG) + if (gradientData->boundingBoxMode && !isPaintingText) { +#else + if (gradientData->boundingBoxMode) { +#endif + FloatRect objectBoundingBox = object->objectBoundingBox(); + transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); + transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); + } + + transform.multiply(gradientData->transform); + gradientData->gradient->setGradientSpaceTransform(transform); + + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + + if (resourceMode & ApplyToFillMode) { + context->setAlpha(svgStyle->fillOpacity()); + context->setFillGradient(gradientData->gradient); + context->setFillRule(svgStyle->fillRule()); + } else if (resourceMode & ApplyToStrokeMode) { + context->setAlpha(svgStyle->strokeOpacity()); + context->setStrokeGradient(gradientData->gradient); + applyStrokeStyleToContext(context, style, object); + } + + return true; +} + +void RenderSVGResourceGradient::postApplyResource(RenderObject* object, GraphicsContext*& context, unsigned short resourceMode) +{ + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + + if (resourceMode & ApplyToTextMode) { +#if PLATFORM(CG) + // CG requires special handling for gradient on text + if (m_savedContext && m_gradient.contains(object)) { + GradientData* gradientData = m_gradient.get(object); + + // Restore on-screen drawing context + context = m_savedContext; + m_savedContext = 0; + + gradientData->gradient->setGradientSpaceTransform(clipToTextMask(context, m_imageBuffer, object, gradientData)); + context->setFillGradient(gradientData->gradient); + + const RenderObject* textRootBlock = findTextRootObject(object); + context->fillRect(textRootBlock->repaintRectInLocalCoordinates()); + + m_imageBuffer.clear(); + } +#else + UNUSED_PARAM(object); +#endif + } else { + if (resourceMode & ApplyToFillMode) + context->fillPath(); + else if (resourceMode & ApplyToStrokeMode) + context->strokePath(); + } + + context->restore(); +} + +void RenderSVGResourceGradient::addStops(GradientData* gradientData, const Vector<Gradient::ColorStop>& stops) const +{ + ASSERT(gradientData->gradient); + + const Vector<Gradient::ColorStop>::const_iterator end = stops.end(); + for (Vector<Gradient::ColorStop>::const_iterator it = stops.begin(); it != end; ++it) + gradientData->gradient->addColorStop(*it); +} + +} + +#endif diff --git a/WebCore/rendering/RenderSVGResourceGradient.h b/WebCore/rendering/RenderSVGResourceGradient.h new file mode 100644 index 0000000..2fd9cf4 --- /dev/null +++ b/WebCore/rendering/RenderSVGResourceGradient.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * 2008 Eric Seidel <eric@webkit.org> + * Copyright (C) Research In Motion Limited 2010. 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 RenderSVGResourceGradient_h +#define RenderSVGResourceGradient_h + +#if ENABLE(SVG) +#include "AffineTransform.h" +#include "FloatRect.h" +#include "Gradient.h" +#include "ImageBuffer.h" +#include "RenderSVGResourceContainer.h" +#include "SVGGradientElement.h" + +#include <wtf/HashMap.h> + +namespace WebCore { + +struct GradientData { + RefPtr<Gradient> gradient; + + bool boundingBoxMode; + AffineTransform transform; +}; + +class GraphicsContext; + +class RenderSVGResourceGradient : public RenderSVGResourceContainer { +public: + RenderSVGResourceGradient(SVGGradientElement*); + virtual ~RenderSVGResourceGradient(); + + virtual void invalidateClients(); + virtual void invalidateClient(RenderObject*); + + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode); + virtual FloatRect resourceBoundingBox(const FloatRect&) const { return FloatRect(); } + +protected: + void addStops(GradientData*, const Vector<Gradient::ColorStop>&) const; + virtual void buildGradient(GradientData*, SVGGradientElement*) const = 0; + +private: + HashMap<RenderObject*, GradientData*> m_gradient; + +#if PLATFORM(CG) + GraphicsContext* m_savedContext; + OwnPtr<ImageBuffer> m_imageBuffer; +#endif +}; + +} + +#endif +#endif diff --git a/WebCore/rendering/RenderSVGResourceLinearGradient.cpp b/WebCore/rendering/RenderSVGResourceLinearGradient.cpp new file mode 100644 index 0000000..e34e524 --- /dev/null +++ b/WebCore/rendering/RenderSVGResourceLinearGradient.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceLinearGradient.h" + +#include "LinearGradientAttributes.h" +#include "SVGLinearGradientElement.h" + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourceLinearGradient::s_resourceType = LinearGradientResourceType; + +RenderSVGResourceLinearGradient::RenderSVGResourceLinearGradient(SVGLinearGradientElement* node) + : RenderSVGResourceGradient(node) +{ +} + +RenderSVGResourceLinearGradient::~RenderSVGResourceLinearGradient() +{ +} + +void RenderSVGResourceLinearGradient::buildGradient(GradientData* gradientData, SVGGradientElement* gradientElement) const +{ + SVGLinearGradientElement* linearGradientElement = static_cast<SVGLinearGradientElement*>(gradientElement); + LinearGradientAttributes attributes = linearGradientElement->collectGradientProperties(); + + // Determine gradient start/end points + FloatPoint startPoint; + FloatPoint endPoint; + linearGradientElement->calculateStartEndPoints(attributes, startPoint, endPoint); + + gradientData->gradient = Gradient::create(startPoint, endPoint); + gradientData->gradient->setSpreadMethod(attributes.spreadMethod()); + + // Record current gradient transform + gradientData->transform = attributes.gradientTransform(); + gradientData->boundingBoxMode = attributes.boundingBoxMode(); + + // Add stops + addStops(gradientData, attributes.stops()); +} + +} + +#endif diff --git a/WebCore/rendering/RenderSVGResourceLinearGradient.h b/WebCore/rendering/RenderSVGResourceLinearGradient.h new file mode 100644 index 0000000..c1f84c2 --- /dev/null +++ b/WebCore/rendering/RenderSVGResourceLinearGradient.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. 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 RenderSVGResourceLinearGradient_h +#define RenderSVGResourceLinearGradient_h + +#if ENABLE(SVG) +#include "RenderSVGResourceGradient.h" + +namespace WebCore { + +class SVGLinearGradientElement; + +class RenderSVGResourceLinearGradient : public RenderSVGResourceGradient { +public: + RenderSVGResourceLinearGradient(SVGLinearGradientElement*); + virtual ~RenderSVGResourceLinearGradient(); + + virtual const char* renderName() const { return "RenderSVGResourceLinearGradient"; } + + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + static RenderSVGResourceType s_resourceType; + + virtual void buildGradient(GradientData*, SVGGradientElement*) const; +}; + +} + +#endif +#endif diff --git a/WebCore/rendering/RenderSVGResourceMarker.cpp b/WebCore/rendering/RenderSVGResourceMarker.cpp index c526962..460239b 100644 --- a/WebCore/rendering/RenderSVGResourceMarker.cpp +++ b/WebCore/rendering/RenderSVGResourceMarker.cpp @@ -35,8 +35,8 @@ namespace WebCore { RenderSVGResourceType RenderSVGResourceMarker::s_resourceType = MarkerResourceType; -RenderSVGResourceMarker::RenderSVGResourceMarker(SVGStyledElement* node) - : RenderSVGResource(node) +RenderSVGResourceMarker::RenderSVGResourceMarker(SVGMarkerElement* node) + : RenderSVGResourceContainer(node) { } @@ -82,6 +82,7 @@ void RenderSVGResourceMarker::invalidateClient(RenderObject* object) return; m_marker.remove(object); + markForLayoutAndResourceInvalidation(object); } void RenderSVGResourceMarker::applyViewportClip(PaintInfo& paintInfo) diff --git a/WebCore/rendering/RenderSVGResourceMarker.h b/WebCore/rendering/RenderSVGResourceMarker.h index 9e39b99..efbbdfa 100644 --- a/WebCore/rendering/RenderSVGResourceMarker.h +++ b/WebCore/rendering/RenderSVGResourceMarker.h @@ -24,7 +24,7 @@ #if ENABLE(SVG) #include "FloatRect.h" #include "RenderObject.h" -#include "RenderSVGResource.h" +#include "RenderSVGResourceContainer.h" #include "SVGMarkerElement.h" #include "SVGStyledElement.h" @@ -34,10 +34,9 @@ namespace WebCore { class AffineTransform; -class RenderSVGResourceMarker : public RenderSVGResource { - +class RenderSVGResourceMarker : public RenderSVGResourceContainer { public: - RenderSVGResourceMarker(SVGStyledElement*); + RenderSVGResourceMarker(SVGMarkerElement*); virtual ~RenderSVGResourceMarker(); virtual const char* renderName() const { return "RenderSVGResourceMarker"; } @@ -58,7 +57,7 @@ public: virtual const AffineTransform& localToParentTransform() const; AffineTransform markerTransformation(const FloatPoint& origin, float angle, float strokeWidth) const; - virtual bool applyResource(RenderObject*, GraphicsContext*&) { return false; } + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short) { return false; } virtual FloatRect resourceBoundingBox(const FloatRect&) const { return FloatRect(); } FloatPoint referencePoint() const; diff --git a/WebCore/rendering/RenderSVGResourceMasker.cpp b/WebCore/rendering/RenderSVGResourceMasker.cpp index 8bb16de..abf8e48 100644 --- a/WebCore/rendering/RenderSVGResourceMasker.cpp +++ b/WebCore/rendering/RenderSVGResourceMasker.cpp @@ -37,13 +37,14 @@ #include "SVGStyledElement.h" #include "SVGUnitTypes.h" #include <wtf/Vector.h> +#include <wtf/UnusedParam.h> namespace WebCore { RenderSVGResourceType RenderSVGResourceMasker::s_resourceType = MaskerResourceType; -RenderSVGResourceMasker::RenderSVGResourceMasker(SVGStyledElement* node) - : RenderSVGResource(node) +RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement* node) + : RenderSVGResourceContainer(node) { } @@ -77,13 +78,19 @@ void RenderSVGResourceMasker::invalidateClient(RenderObject* object) if (!m_masker.contains(object)) return; - delete m_masker.take(object); + delete m_masker.take(object); + markForLayoutAndResourceInvalidation(object); } -bool RenderSVGResourceMasker::applyResource(RenderObject* object, GraphicsContext*& context) +bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(object); ASSERT(context); +#ifndef NDEBUG + ASSERT(resourceMode == ApplyToDefaultMode); +#else + UNUSED_PARAM(resourceMode); +#endif if (!m_masker.contains(object)) m_masker.set(object, new MaskerData); @@ -151,7 +158,7 @@ void RenderSVGResourceMasker::createMaskImage(MaskerData* maskerData, const SVGM maskImageRect.setLocation(IntPoint()); // Don't create ImageBuffers with image size of 0 - if (!maskImageRect.width() || !maskImageRect.height()) { + if (maskImageRect.isEmpty()) { maskerData->emptyMask = true; return; } diff --git a/WebCore/rendering/RenderSVGResourceMasker.h b/WebCore/rendering/RenderSVGResourceMasker.h index 3127e3c..b022f7b 100644 --- a/WebCore/rendering/RenderSVGResourceMasker.h +++ b/WebCore/rendering/RenderSVGResourceMasker.h @@ -26,7 +26,7 @@ #include "GraphicsContext.h" #include "ImageBuffer.h" #include "IntSize.h" -#include "RenderSVGResource.h" +#include "RenderSVGResourceContainer.h" #include "SVGMaskElement.h" #include "SVGUnitTypes.h" @@ -36,9 +36,8 @@ namespace WebCore { struct MaskerData { - MaskerData(FloatRect rect = FloatRect(), bool emptyObject = false) - : maskRect(rect) - , emptyMask(emptyObject) + MaskerData() + : emptyMask(false) { } @@ -47,10 +46,9 @@ struct MaskerData { bool emptyMask; }; -class RenderSVGResourceMasker : public RenderSVGResource { - +class RenderSVGResourceMasker : public RenderSVGResourceContainer { public: - RenderSVGResourceMasker(SVGStyledElement*); + RenderSVGResourceMasker(SVGMaskElement*); virtual ~RenderSVGResourceMasker(); virtual const char* renderName() const { return "RenderSVGResourceMasker"; } @@ -58,7 +56,7 @@ public: virtual void invalidateClients(); virtual void invalidateClient(RenderObject*); - virtual bool applyResource(RenderObject*, GraphicsContext*&); + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); virtual FloatRect resourceBoundingBox(const FloatRect&) const; SVGUnitTypes::SVGUnitType maskUnits() const { return toUnitType(static_cast<SVGMaskElement*>(node())->maskUnits()); } diff --git a/WebCore/rendering/RenderSVGResourcePattern.cpp b/WebCore/rendering/RenderSVGResourcePattern.cpp new file mode 100644 index 0000000..8302030 --- /dev/null +++ b/WebCore/rendering/RenderSVGResourcePattern.cpp @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourcePattern.h" + +#include "GraphicsContext.h" +#include "PatternAttributes.h" +#include "SVGRenderSupport.h" + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourcePattern::s_resourceType = PatternResourceType; + +RenderSVGResourcePattern::RenderSVGResourcePattern(SVGPatternElement* node) + : RenderSVGResourceContainer(node) +{ +} + +RenderSVGResourcePattern::~RenderSVGResourcePattern() +{ + deleteAllValues(m_pattern); + m_pattern.clear(); +} + +void RenderSVGResourcePattern::invalidateClients() +{ + const HashMap<RenderObject*, PatternData*>::const_iterator end = m_pattern.end(); + for (HashMap<RenderObject*, PatternData*>::const_iterator it = m_pattern.begin(); it != end; ++it) + markForLayoutAndResourceInvalidation(it->first); + + deleteAllValues(m_pattern); + m_pattern.clear(); +} + +void RenderSVGResourcePattern::invalidateClient(RenderObject* object) +{ + ASSERT(object); + + // FIXME: The HashMap should always contain the object on calling invalidateClient. A race condition + // during the parsing can causes a call of invalidateClient right before the call of applyResource. + // We return earlier for the moment. This bug should be fixed in: + // https://bugs.webkit.org/show_bug.cgi?id=35181 + if (!m_pattern.contains(object)) + return; + + delete m_pattern.take(object); + markForLayoutAndResourceInvalidation(object); +} + +bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode) +{ + ASSERT(object); + ASSERT(style); + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + + // Be sure to synchronize all SVG properties on the patternElement _before_ processing any further. + // Otherwhise the call to collectPatternAttributes() in createTileImage(), may cause the SVG DOM property + // synchronization to kick in, which causes invalidateClients() to be called, which in turn deletes our + // PatternData object! Leaving out the line below will cause svg/dynamic-updates/SVGPatternElement-svgdom* to crash. + SVGPatternElement* patternElement = static_cast<SVGPatternElement*>(node()); + if (!patternElement) + return false; + + patternElement->updateAnimatedSVGAttribute(anyQName()); + + if (!m_pattern.contains(object)) + m_pattern.set(object, new PatternData); + + PatternData* patternData = m_pattern.get(object); + if (!patternData->pattern) { + FloatRect patternBoundaries; + AffineTransform patternTransform; + + // Create tile image + OwnPtr<ImageBuffer> tileImage = createTileImage(patternBoundaries, patternTransform, patternElement, object); + if (!tileImage) + return false; + + // Create pattern object + buildPattern(patternData, patternBoundaries, tileImage.release()); + + if (!patternData->pattern) + return false; + + // Compute pattern transformation + AffineTransform transform; + transform.translate(patternBoundaries.x(), patternBoundaries.y()); + transform.multiply(patternTransform); + patternData->pattern->setPatternSpaceTransform(transform); + } + + // Draw pattern + context->save(); + + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + + if (resourceMode & ApplyToFillMode) { + context->setAlpha(svgStyle->fillOpacity()); + context->setFillPattern(patternData->pattern); + context->setFillRule(svgStyle->fillRule()); + } else if (resourceMode & ApplyToStrokeMode) { + context->setAlpha(svgStyle->strokeOpacity()); + context->setStrokePattern(patternData->pattern); + applyStrokeStyleToContext(context, style, object); + } + + if (resourceMode & ApplyToTextMode) { + if (resourceMode & ApplyToFillMode) { + context->setTextDrawingMode(cTextFill); + +#if PLATFORM(CG) + context->applyFillPattern(); +#endif + } else if (resourceMode & ApplyToStrokeMode) { + context->setTextDrawingMode(cTextStroke); + +#if PLATFORM(CG) + context->applyStrokePattern(); +#endif + } + } + + return true; +} + +void RenderSVGResourcePattern::postApplyResource(RenderObject*, GraphicsContext*& context, unsigned short resourceMode) +{ + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + + if (!(resourceMode & ApplyToTextMode)) { + if (resourceMode & ApplyToFillMode) + context->fillPath(); + else if (resourceMode & ApplyToStrokeMode) + context->strokePath(); + } + + context->restore(); +} + +static inline FloatRect calculatePatternBoundaries(PatternAttributes& attributes, + const FloatRect& objectBoundingBox, + const SVGPatternElement* patternElement) +{ + if (attributes.boundingBoxMode()) + return FloatRect(attributes.x().valueAsPercentage() * objectBoundingBox.width(), + attributes.y().valueAsPercentage() * objectBoundingBox.height(), + attributes.width().valueAsPercentage() * objectBoundingBox.width(), + attributes.height().valueAsPercentage() * objectBoundingBox.height()); + + return FloatRect(attributes.x().value(patternElement), + attributes.y().value(patternElement), + attributes.width().value(patternElement), + attributes.height().value(patternElement)); +} + +FloatRect RenderSVGResourcePattern::calculatePatternBoundariesIncludingOverflow(PatternAttributes& attributes, + const FloatRect& objectBoundingBox, + const AffineTransform& viewBoxCTM, + const FloatRect& patternBoundaries) const +{ + // Eventually calculate the pattern content boundaries (only needed with overflow="visible"). + FloatRect patternContentBoundaries; + + const RenderStyle* style = this->style(); + if (style->overflowX() == OVISIBLE && style->overflowY() == OVISIBLE) { + for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) { + if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyledTransformable() || !node->renderer()) + continue; + patternContentBoundaries.unite(node->renderer()->repaintRectInLocalCoordinates()); + } + } + + if (patternContentBoundaries.isEmpty()) + return patternBoundaries; + + FloatRect patternBoundariesIncludingOverflow = patternBoundaries; + + // Respect objectBoundingBoxMode for patternContentUnits, if viewBox is not set. + if (!viewBoxCTM.isIdentity()) + patternContentBoundaries = viewBoxCTM.mapRect(patternContentBoundaries); + else if (attributes.boundingBoxModeContent()) + patternContentBoundaries = FloatRect(patternContentBoundaries.x() * objectBoundingBox.width(), + patternContentBoundaries.y() * objectBoundingBox.height(), + patternContentBoundaries.width() * objectBoundingBox.width(), + patternContentBoundaries.height() * objectBoundingBox.height()); + + patternBoundariesIncludingOverflow.unite(patternContentBoundaries); + return patternBoundariesIncludingOverflow; +} + +PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(FloatRect& patternBoundaries, + AffineTransform& patternTransform, + const SVGPatternElement* patternElement, + RenderObject* object) const +{ + PatternAttributes attributes = patternElement->collectPatternProperties(); + + // If we couldn't determine the pattern content element root, stop here. + if (!attributes.patternContentElement()) + return 0; + + FloatRect objectBoundingBox = object->objectBoundingBox(); + patternBoundaries = calculatePatternBoundaries(attributes, objectBoundingBox, patternElement); + patternTransform = attributes.patternTransform(); + + AffineTransform viewBoxCTM = patternElement->viewBoxToViewTransform(patternElement->viewBox(), + patternElement->preserveAspectRatio(), + patternBoundaries.width(), + patternBoundaries.height()); + + FloatRect patternBoundariesIncludingOverflow = calculatePatternBoundariesIncludingOverflow(attributes, + objectBoundingBox, + viewBoxCTM, + patternBoundaries); + + IntSize imageSize(lroundf(patternBoundariesIncludingOverflow.width()), lroundf(patternBoundariesIncludingOverflow.height())); + + // FIXME: We should be able to clip this more, needs investigation + clampImageBufferSizeToViewport(object->document()->view(), imageSize); + + // Don't create ImageBuffers with image size of 0 + if (imageSize.isEmpty()) + return 0; + + OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(imageSize); + + GraphicsContext* context = tileImage->context(); + ASSERT(context); + + context->save(); + + // Translate to pattern start origin + if (patternBoundariesIncludingOverflow.location() != patternBoundaries.location()) { + context->translate(patternBoundaries.x() - patternBoundariesIncludingOverflow.x(), + patternBoundaries.y() - patternBoundariesIncludingOverflow.y()); + + patternBoundaries.setLocation(patternBoundariesIncludingOverflow.location()); + } + + // Process viewBox or boundingBoxModeContent correction + if (!viewBoxCTM.isIdentity()) + context->concatCTM(viewBoxCTM); + else if (attributes.boundingBoxModeContent()) { + context->translate(objectBoundingBox.x(), objectBoundingBox.y()); + context->scale(FloatSize(objectBoundingBox.width(), objectBoundingBox.height())); + } + + // Render subtree into ImageBuffer + for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) { + if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !node->renderer()) + continue; + renderSubtreeToImage(tileImage.get(), node->renderer()); + } + + context->restore(); + return tileImage.release(); +} + +void RenderSVGResourcePattern::buildPattern(PatternData* patternData, const FloatRect& patternBoundaries, PassOwnPtr<ImageBuffer> tileImage) const +{ + if (!tileImage->image()) { + patternData->pattern = 0; + return; + } + + IntRect tileRect = tileImage->image()->rect(); + if (tileRect.width() <= patternBoundaries.width() && tileRect.height() <= patternBoundaries.height()) { + patternData->pattern = Pattern::create(tileImage->image(), true, true); + return; + } + + // Draw the first cell of the pattern manually to support overflow="visible" on all platforms. + int tileWidth = static_cast<int>(patternBoundaries.width() + 0.5f); + int tileHeight = static_cast<int>(patternBoundaries.height() + 0.5f); + + // Don't create ImageBuffers with image size of 0 + if (!tileWidth || !tileHeight) { + patternData->pattern = 0; + return; + } + + OwnPtr<ImageBuffer> newTileImage = ImageBuffer::create(IntSize(tileWidth, tileHeight)); + GraphicsContext* newTileImageContext = newTileImage->context(); + + int numY = static_cast<int>(ceilf(tileRect.height() / tileHeight)) + 1; + int numX = static_cast<int>(ceilf(tileRect.width() / tileWidth)) + 1; + + newTileImageContext->save(); + newTileImageContext->translate(-patternBoundaries.width() * numX, -patternBoundaries.height() * numY); + for (int i = numY; i > 0; --i) { + newTileImageContext->translate(0, patternBoundaries.height()); + for (int j = numX; j > 0; --j) { + newTileImageContext->translate(patternBoundaries.width(), 0); + newTileImageContext->drawImage(tileImage->image(), style()->colorSpace(), tileRect, tileRect); + } + newTileImageContext->translate(-patternBoundaries.width() * numX, 0); + } + newTileImageContext->restore(); + + patternData->pattern = Pattern::create(newTileImage->image(), true, true); +} + +} + +#endif diff --git a/WebCore/rendering/RenderSVGResourcePattern.h b/WebCore/rendering/RenderSVGResourcePattern.h new file mode 100644 index 0000000..2f9d553 --- /dev/null +++ b/WebCore/rendering/RenderSVGResourcePattern.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. 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 RenderSVGResourcePattern_h +#define RenderSVGResourcePattern_h + +#if ENABLE(SVG) +#include "AffineTransform.h" +#include "FloatRect.h" +#include "ImageBuffer.h" +#include "Pattern.h" +#include "RenderSVGResourceContainer.h" +#include "SVGPatternElement.h" +#include "SVGUnitTypes.h" + +#include <wtf/HashMap.h> +#include <wtf/OwnPtr.h> + +namespace WebCore { + +struct PatternData { + RefPtr<Pattern> pattern; +}; + +struct PatternAttributes; + +class RenderSVGResourcePattern : public RenderSVGResourceContainer { +public: + RenderSVGResourcePattern(SVGPatternElement*); + virtual ~RenderSVGResourcePattern(); + + virtual const char* renderName() const { return "RenderSVGResourcePattern"; } + + virtual void invalidateClients(); + virtual void invalidateClient(RenderObject*); + + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode); + virtual FloatRect resourceBoundingBox(const FloatRect&) const { return FloatRect(); } + + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + static RenderSVGResourceType s_resourceType; + +private: + PassOwnPtr<ImageBuffer> createTileImage(FloatRect& patternBoundaries, AffineTransform& patternTransform, const SVGPatternElement*, RenderObject*) const; + void buildPattern(PatternData*, const FloatRect& patternBoundaries, PassOwnPtr<ImageBuffer> tileImage) const; + FloatRect calculatePatternBoundariesIncludingOverflow(PatternAttributes&, const FloatRect& objectBoundingBox, + const AffineTransform& viewBoxCTM, const FloatRect& patternBoundaries) const; + + HashMap<RenderObject*, PatternData*> m_pattern; +}; + +} + +#endif +#endif diff --git a/WebCore/rendering/RenderSVGResourceRadialGradient.cpp b/WebCore/rendering/RenderSVGResourceRadialGradient.cpp new file mode 100644 index 0000000..a8904c8 --- /dev/null +++ b/WebCore/rendering/RenderSVGResourceRadialGradient.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceRadialGradient.h" + +#include "RadialGradientAttributes.h" +#include "SVGRadialGradientElement.h" + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourceRadialGradient::s_resourceType = RadialGradientResourceType; + +RenderSVGResourceRadialGradient::RenderSVGResourceRadialGradient(SVGRadialGradientElement* node) + : RenderSVGResourceGradient(node) +{ +} + +RenderSVGResourceRadialGradient::~RenderSVGResourceRadialGradient() +{ +} + +void RenderSVGResourceRadialGradient::buildGradient(GradientData* gradientData, SVGGradientElement* gradientElement) const +{ + SVGRadialGradientElement* radialGradientElement = static_cast<SVGRadialGradientElement*>(gradientElement); + RadialGradientAttributes attributes = radialGradientElement->collectGradientProperties(); + + // Determine gradient focal/center points and radius + FloatPoint focalPoint; + FloatPoint centerPoint; + float radius; + radialGradientElement->calculateFocalCenterPointsAndRadius(attributes, focalPoint, centerPoint, radius); + + gradientData->gradient = Gradient::create(focalPoint, + 0.0f, // SVG does not support a "focus radius" + centerPoint, + radius); + + gradientData->gradient->setSpreadMethod(attributes.spreadMethod()); + + // Record current gradient transform + gradientData->transform = attributes.gradientTransform(); + gradientData->boundingBoxMode = attributes.boundingBoxMode(); + + // Add stops + addStops(gradientData, attributes.stops()); +} + +} + +#endif diff --git a/WebCore/rendering/RenderSVGResourceRadialGradient.h b/WebCore/rendering/RenderSVGResourceRadialGradient.h new file mode 100644 index 0000000..0583f99 --- /dev/null +++ b/WebCore/rendering/RenderSVGResourceRadialGradient.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. 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 RenderSVGResourceRadialGradient_h +#define RenderSVGResourceRadialGradient_h + +#if ENABLE(SVG) +#include "RenderSVGResourceGradient.h" + +namespace WebCore { + +class SVGRadialGradientElement; + +class RenderSVGResourceRadialGradient : public RenderSVGResourceGradient { +public: + RenderSVGResourceRadialGradient(SVGRadialGradientElement*); + virtual ~RenderSVGResourceRadialGradient(); + + virtual const char* renderName() const { return "RenderSVGResourceRadialGradient"; } + + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + static RenderSVGResourceType s_resourceType; + + virtual void buildGradient(GradientData*, SVGGradientElement*) const; +}; + +} + +#endif +#endif diff --git a/WebCore/rendering/RenderSVGResourceSolidColor.cpp b/WebCore/rendering/RenderSVGResourceSolidColor.cpp new file mode 100644 index 0000000..9d34d79 --- /dev/null +++ b/WebCore/rendering/RenderSVGResourceSolidColor.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceSolidColor.h" + +#include "GraphicsContext.h" +#include "SVGRenderSupport.h" + +#if PLATFORM(SKIA) +#include "PlatformContextSkia.h" +#endif + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourceSolidColor::s_resourceType = SolidColorResourceType; + +RenderSVGResourceSolidColor::RenderSVGResourceSolidColor() +{ +} + +RenderSVGResourceSolidColor::~RenderSVGResourceSolidColor() +{ +} + +bool RenderSVGResourceSolidColor::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode) +{ + // We are NOT allowed to ASSERT(object) here, unlike all other resources. + // RenderSVGResourceSolidColor is the only resource which may be used from HTML, when rendering + // SVG Fonts for a HTML document. This will be indicated by a null RenderObject pointer. + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + + const SVGRenderStyle* svgStyle = style ? style->svgStyle() : 0; + ColorSpace colorSpace = style ? style->colorSpace() : DeviceColorSpace; + + if (resourceMode & ApplyToFillMode) { + context->setAlpha(svgStyle ? svgStyle->fillOpacity() : 1.0f); + context->setFillColor(m_color, colorSpace); + context->setFillRule(svgStyle ? svgStyle->fillRule() : RULE_NONZERO); + + if (resourceMode & ApplyToTextMode) + context->setTextDrawingMode(cTextFill); + } else if (resourceMode & ApplyToStrokeMode) { + context->setAlpha(svgStyle ? svgStyle->strokeOpacity() : 1.0f); + context->setStrokeColor(m_color, colorSpace); + + if (style) + applyStrokeStyleToContext(context, style, object); + + if (resourceMode & ApplyToTextMode) + context->setTextDrawingMode(cTextStroke); + } + + return true; +} + +void RenderSVGResourceSolidColor::postApplyResource(RenderObject*, GraphicsContext*& context, unsigned short resourceMode) +{ + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + + if (!(resourceMode & ApplyToTextMode)) { + if (resourceMode & ApplyToFillMode) + context->fillPath(); + else if (resourceMode & ApplyToStrokeMode) + context->strokePath(); + } + +#if PLATFORM(SKIA) + // FIXME: Move this into the GraphicsContext + // WebKit implicitly expects us to reset the path. + // For example in fillAndStrokePath() of RenderPath.cpp the path is + // added back to the context after filling. This is because internally it + // calls CGContextFillPath() which closes the path. + context->beginPath(); + context->platformContext()->setFillShader(0); + context->platformContext()->setStrokeShader(0); +#endif +} + +} + +#endif diff --git a/WebCore/rendering/RenderSVGResourceSolidColor.h b/WebCore/rendering/RenderSVGResourceSolidColor.h new file mode 100644 index 0000000..a1a8863 --- /dev/null +++ b/WebCore/rendering/RenderSVGResourceSolidColor.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) Research In Motion Limited 2010. 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 RenderSVGResourceSolidColor_h +#define RenderSVGResourceSolidColor_h + +#if ENABLE(SVG) +#include "Color.h" +#include "FloatRect.h" +#include "RenderSVGResource.h" + +namespace WebCore { + +class RenderSVGResourceSolidColor : public RenderSVGResource { +public: + RenderSVGResourceSolidColor(); + virtual ~RenderSVGResourceSolidColor(); + + virtual void invalidateClients() { } + virtual void invalidateClient(RenderObject*) { } + + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode); + virtual FloatRect resourceBoundingBox(const FloatRect&) const { return FloatRect(); } + + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + static RenderSVGResourceType s_resourceType; + + const Color& color() const { return m_color; } + void setColor(const Color& color) { m_color = color; } + +private: + Color m_color; +}; + +} + +#endif +#endif diff --git a/WebCore/rendering/RenderSVGRoot.cpp b/WebCore/rendering/RenderSVGRoot.cpp index 5ed0871..67a3b2a 100644 --- a/WebCore/rendering/RenderSVGRoot.cpp +++ b/WebCore/rendering/RenderSVGRoot.cpp @@ -62,11 +62,11 @@ void RenderSVGRoot::calcPrefWidths() { ASSERT(prefWidthsDirty()); - int paddingAndBorders = paddingLeft() + paddingRight() + borderLeft() + borderRight(); - int width = calcReplacedWidth(false) + paddingAndBorders; + int borderAndPadding = borderAndPaddingWidth(); + int width = calcReplacedWidth(false) + borderAndPadding; if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) - width = min(width, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? paddingAndBorders : 0)); + width = min(width, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : 0)); if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent())) { m_minPrefWidth = 0; diff --git a/WebCore/rendering/RenderSVGText.cpp b/WebCore/rendering/RenderSVGText.cpp index c0c4650..966196b 100644 --- a/WebCore/rendering/RenderSVGText.cpp +++ b/WebCore/rendering/RenderSVGText.cpp @@ -160,7 +160,10 @@ void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads) } void RenderSVGText::paint(PaintInfo& paintInfo, int, int) -{ +{ + if (paintInfo.context->paintingDisabled()) + return; + PaintInfo pi(paintInfo); pi.context->save(); applyTransformToPaintInfo(pi, localToParentTransform()); diff --git a/WebCore/rendering/RenderSVGText.h b/WebCore/rendering/RenderSVGText.h index fe53086..66f7eb3 100644 --- a/WebCore/rendering/RenderSVGText.h +++ b/WebCore/rendering/RenderSVGText.h @@ -42,8 +42,6 @@ public: private: virtual const char* renderName() const { return "RenderSVGText"; } - virtual const SVGRenderBase* toSVGRenderBase() const { return this; } - virtual bool isSVGText() const { return true; } virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } diff --git a/WebCore/rendering/RenderSlider.cpp b/WebCore/rendering/RenderSlider.cpp index 37b5e19..ed5fe76 100644 --- a/WebCore/rendering/RenderSlider.cpp +++ b/WebCore/rendering/RenderSlider.cpp @@ -30,6 +30,7 @@ #include "HTMLInputElement.h" #include "HTMLDivElement.h" #include "HTMLNames.h" +#include "HTMLParser.h" #include "MediaControlElements.h" #include "MouseEvent.h" #include "RenderLayer.h" @@ -186,7 +187,7 @@ void RenderSlider::calcPrefWidths() m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); } - int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight(); + int toAdd = borderAndPaddingWidth(); m_minPrefWidth += toAdd; m_maxPrefWidth += toAdd; @@ -260,8 +261,7 @@ void RenderSlider::layout() RenderBox* thumb = m_thumb ? toRenderBox(m_thumb->renderer()) : 0; - IntSize baseSize(borderLeft() + paddingLeft() + paddingRight() + borderRight(), - borderTop() + paddingTop() + paddingBottom() + borderBottom()); + IntSize baseSize(borderAndPaddingWidth(), borderAndPaddingHeight()); if (thumb) { // Allow the theme to set the size of the thumb. @@ -314,7 +314,7 @@ void RenderSlider::updateFromElement() m_thumb->setRenderer(m_thumb->createRenderer(renderArena(), thumbStyle.get())); m_thumb->renderer()->setStyle(thumbStyle.release()); m_thumb->setAttached(); - m_thumb->setInDocument(true); + m_thumb->setInDocument(); addChild(m_thumb->renderer()); } setNeedsLayout(true); @@ -361,7 +361,7 @@ void RenderSlider::setValueForPosition(int position) if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart) fraction = 1 - fraction; double value = range.clampValue(range.valueFromProportion(fraction)); - element->setValueFromRenderer(HTMLInputElement::serializeForNumberType(value)); + element->setValueFromRenderer(serializeForNumberType(value)); // Also update the position if appropriate. if (position != currentPosition()) { diff --git a/WebCore/rendering/RenderTableCell.cpp b/WebCore/rendering/RenderTableCell.cpp index 4506e77..5779422 100644 --- a/WebCore/rendering/RenderTableCell.cpp +++ b/WebCore/rendering/RenderTableCell.cpp @@ -120,7 +120,7 @@ Length RenderTableCell::styleOrColWidth() const // Percentages don't need to be handled since they're always treated this way (even when specified on the cells). // See Bugzilla bug 8126 for details. if (colWidthSum.isFixed() && colWidthSum.value() > 0) - colWidthSum = Length(max(0, colWidthSum.value() - borderLeft() - borderRight() - paddingLeft() - paddingRight()), Fixed); + colWidthSum = Length(max(0, colWidthSum.value() - borderAndPaddingWidth()), Fixed); return colWidthSum; } diff --git a/WebCore/rendering/RenderText.cpp b/WebCore/rendering/RenderText.cpp index 90ad6d8..bede6a6 100644 --- a/WebCore/rendering/RenderText.cpp +++ b/WebCore/rendering/RenderText.cpp @@ -455,23 +455,40 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e *extraWidthToEndOfLine = (box->root()->width() + rootLeft) - (left + 1); RenderBlock* cb = containingBlock(); + RenderStyle* cbStyle = cb->style(); + int leftEdge; + int rightEdge; if (style()->autoWrap()) { - int availableWidth = cb->lineWidth(top, false); - if (box->direction() == LTR) - left = min(left, rootLeft + availableWidth - caretWidthRightOfOffset); - else - left = max(left, cb->x()); + leftEdge = cb->x(); + rightEdge = cb->frameRect().right(); } else { - // If there is no wrapping, the caret can leave its containing block, but not its root line box. - if (cb->style()->direction() == LTR) { - int rightEdge = max(cb->width(), rootRight); - left = min(left, rightEdge - caretWidthRightOfOffset); - left = max(left, rootLeft); - } else { - int leftEdge = min(cb->x(), rootLeft); - left = max(left, leftEdge); - left = min(left, rootRight - caretWidth); - } + leftEdge = min(cb->x(), rootLeft); + rightEdge = max(cb->frameRect().right(), rootRight); + } + + bool rightAligned = false; + switch (cbStyle->textAlign()) { + case TAAUTO: + case JUSTIFY: + rightAligned = cbStyle->direction() == RTL; + break; + case RIGHT: + case WEBKIT_RIGHT: + rightAligned = true; + break; + case LEFT: + case WEBKIT_LEFT: + case CENTER: + case WEBKIT_CENTER: + break; + } + + if (rightAligned) { + left = max(left, leftEdge); + left = min(left, rootRight - caretWidth); + } else { + left = min(left, rightEdge - caretWidthRightOfOffset); + left = max(left, rootLeft); } return IntRect(left, top, caretWidth, height); diff --git a/WebCore/rendering/RenderTextControl.cpp b/WebCore/rendering/RenderTextControl.cpp index 5e19362..1e80ff0 100644 --- a/WebCore/rendering/RenderTextControl.cpp +++ b/WebCore/rendering/RenderTextControl.cpp @@ -151,13 +151,12 @@ void RenderTextControl::createSubtreeIfNeeded(TextControlInnerElement* innerBloc int RenderTextControl::textBlockHeight() const { - return height() - paddingTop() - paddingBottom() - borderTop() - borderBottom(); + return height() - borderAndPaddingHeight(); } int RenderTextControl::textBlockWidth() const { - return width() - paddingLeft() - paddingRight() - borderLeft() - borderRight() - - m_innerText->renderBox()->paddingLeft() - m_innerText->renderBox()->paddingRight(); + return width() - borderAndPaddingWidth() - m_innerText->renderBox()->paddingLeft() - m_innerText->renderBox()->paddingRight(); } void RenderTextControl::updateFromElement() @@ -410,7 +409,7 @@ void RenderTextControl::calcHeight() m_innerText->renderBox()->marginTop() + m_innerText->renderBox()->marginBottom()); adjustControlHeightBasedOnLineHeight(m_innerText->renderer()->lineHeight(true, true)); - setHeight(height() + paddingTop() + paddingBottom() + borderTop() + borderBottom()); + setHeight(height() + borderAndPaddingHeight()); // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap. if (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && m_innerText->renderer()->style()->wordWrap() == NormalWordWrap)) @@ -434,13 +433,6 @@ void RenderTextControl::forwardEvent(Event* event) m_innerText->defaultEventHandler(event); } -IntRect RenderTextControl::controlClipRect(int tx, int ty) const -{ - IntRect clipRect = contentBoxRect(); - clipRect.move(tx, ty); - return clipRect; -} - static const char* fontFamiliesWithInvalidCharWidth[] = { "American Typewriter", "Arial Hebrew", @@ -541,7 +533,7 @@ void RenderTextControl::calcPrefWidths() m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); } - int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight(); + int toAdd = borderAndPaddingWidth(); m_minPrefWidth += toAdd; m_maxPrefWidth += toAdd; diff --git a/WebCore/rendering/RenderTextControl.h b/WebCore/rendering/RenderTextControl.h index 2fc8edc..b76d1f2 100644 --- a/WebCore/rendering/RenderTextControl.h +++ b/WebCore/rendering/RenderTextControl.h @@ -95,8 +95,6 @@ protected: 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; } diff --git a/WebCore/rendering/RenderTextControlSingleLine.cpp b/WebCore/rendering/RenderTextControlSingleLine.cpp index 4edd203..37d44c4 100644 --- a/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved. * (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or @@ -66,6 +66,9 @@ RenderTextControlSingleLine::~RenderTextControlSingleLine() if (m_innerBlock) m_innerBlock->detach(); + + if (m_outerSpinButton) + m_outerSpinButton->detach(); } RenderStyle* RenderTextControlSingleLine::textBaseStyle() const @@ -185,12 +188,27 @@ void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, int tx, int ty) if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) { IntRect contentsRect = contentBoxRect(); + // Center vertically like the text. + contentsRect.setY((height() - contentsRect.height()) / 2); + // Convert the rect into the coords used for painting the content contentsRect.move(tx + x(), ty + y()); theme()->paintCapsLockIndicator(this, paintInfo, contentsRect); } } +void RenderTextControlSingleLine::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) +{ + paintBoxDecorationsWithSize(paintInfo, tx, ty, width() - decorationWidthRight(), height()); +} + +void RenderTextControlSingleLine::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty) +{ + int w = width() - decorationWidthRight(); + if (w && height()) + rects.append(IntRect(tx, ty, w, height())); +} + void RenderTextControlSingleLine::layout() { int oldHeight = height(); @@ -234,7 +252,7 @@ void RenderTextControlSingleLine::layout() innerTextRenderer->style()->setWidth(Length(desiredWidth, Fixed)); if (m_innerBlock) { - int innerBlockWidth = width() - paddingLeft() - paddingRight() - borderLeft() - borderRight(); + int innerBlockWidth = width() - borderAndPaddingWidth(); if (innerBlockWidth != innerBlockRenderer->width()) relayoutChildren = true; innerBlockRenderer->style()->setWidth(Length(innerBlockWidth, Fixed)); @@ -246,7 +264,18 @@ void RenderTextControlSingleLine::layout() RenderBox* childBlock = innerBlockRenderer ? innerBlockRenderer : innerTextRenderer; currentHeight = childBlock->height(); if (currentHeight < height()) - childBlock->setLocation(childBlock->x(), (height() - currentHeight) / 2); + childBlock->setY((height() - currentHeight) / 2); + + // Center the spin button vertically, and move it to the right by + // padding + border of the text fields. + if (RenderBox* spinBox = m_outerSpinButton ? m_outerSpinButton->renderBox() : 0) { + int diff = height() - spinBox->height(); + // If the diff is odd, the top area over the spin button takes the + // remaining one pixel. It's good for Mac NSStepper because it has + // shadow at the bottom. + int y = (diff / 2) + (diff % 2); + spinBox->setLocation(spinBox->x() + paddingRight() + borderRight(), y); + } } bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction hitTestAction) @@ -266,6 +295,9 @@ bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, Hit if (result.innerNode()->isDescendantOf(innerTextElement()) || result.innerNode() == node()) hitInnerTextElement(result, xPos, yPos, tx, ty); + // If we found a spin button, we're done. + if (m_outerSpinButton && result.innerNode() == m_outerSpinButton) + return true; // If we're not a search field, or we already found the results or cancel buttons, we're done. if (!m_innerBlock || result.innerNode() == m_resultsButton || result.innerNode() == m_cancelButton) return true; @@ -316,10 +348,13 @@ void RenderTextControlSingleLine::forwardEvent(Event* event) } FloatPoint localPoint = innerTextRenderer->absoluteToLocal(static_cast<MouseEvent*>(event)->absoluteLocation(), false, true); + int textRight = innerTextRenderer->borderBoxRect().right(); if (m_resultsButton && localPoint.x() < innerTextRenderer->borderBoxRect().x()) m_resultsButton->defaultEventHandler(event); - else if (m_cancelButton && localPoint.x() > innerTextRenderer->borderBoxRect().right()) + else if (m_cancelButton && localPoint.x() > textRight) m_cancelButton->defaultEventHandler(event); + else if (m_outerSpinButton && localPoint.x() > textRight) + m_outerSpinButton->defaultEventHandler(event); else RenderTextControl::forwardEvent(event); } @@ -342,6 +377,9 @@ void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const Ren if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) cancelRenderer->setStyle(createCancelButtonStyle(style())); + if (RenderObject* spinRenderer = m_outerSpinButton ? m_outerSpinButton->renderer() : 0) + spinRenderer->setStyle(createOuterSpinButtonStyle()); + setHasOverflowClip(false); } @@ -369,6 +407,16 @@ void RenderTextControlSingleLine::capsLockStateMayHaveChanged() } } +IntRect RenderTextControlSingleLine::controlClipRect(int tx, int ty) const +{ + // This should only get called for search inputs. + ASSERT(hasControlClip()); + + IntRect clipRect = IntRect(m_innerBlock->renderBox()->frameRect()); + clipRect.move(tx, ty); + return clipRect; +} + int RenderTextControlSingleLine::textBlockWidth() const { int width = RenderTextControl::textBlockWidth(); @@ -383,6 +431,18 @@ int RenderTextControlSingleLine::textBlockWidth() const width -= cancelRenderer->width() + cancelRenderer->marginLeft() + cancelRenderer->marginRight(); } + return width - decorationWidthRight(); +} + +int RenderTextControlSingleLine::decorationWidthRight() const +{ + int width = 0; + if (RenderBox* spinRenderer = m_outerSpinButton ? m_outerSpinButton->renderBox() : 0) { + spinRenderer->calcWidth(); + width += spinRenderer->width() + spinRenderer->marginLeft() + spinRenderer->marginRight(); + } + if (width > 0) + width += paddingRight() + borderRight(); return width; } @@ -432,6 +492,18 @@ int RenderTextControlSingleLine::preferredContentWidth(float charWidth) const return result; } +int RenderTextControlSingleLine::preferredDecorationWidthRight() const +{ + int width = 0; + if (RenderBox* spinRenderer = m_outerSpinButton ? m_outerSpinButton->renderBox() : 0) { + spinRenderer->calcWidth(); + width += spinRenderer->minPrefWidth() + spinRenderer->marginLeft() + spinRenderer->marginRight(); + } + if (width > 0) + width += paddingRight() + borderRight(); + return width; +} + void RenderTextControlSingleLine::adjustControlHeightBasedOnLineHeight(int lineHeight) { if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) { @@ -459,6 +531,10 @@ void RenderTextControlSingleLine::createSubtreeIfNeeded() { if (!inputElement()->isSearchField()) { RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get()); + if (inputElement()->hasSpinButton() && !m_outerSpinButton) { + m_outerSpinButton = new SpinButtonElement(document(), node()); + m_outerSpinButton->attachInnerElement(node(), createOuterSpinButtonStyle(), renderArena()); + } return; } @@ -535,7 +611,7 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const if (textBlockStyle->font().lineSpacing() > lineHeight(true, true)) textBlockStyle->setLineHeight(Length(-100.0f, Percent)); - textBlockStyle->setDisplay(m_innerBlock ? INLINE_BLOCK : BLOCK); + textBlockStyle->setDisplay(m_innerBlock || inputElement()->hasSpinButton() ? INLINE_BLOCK : BLOCK); // We're adding one extra pixel of padding to match WinIE. textBlockStyle->setPaddingLeft(Length(1, Fixed)); @@ -607,6 +683,16 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createCancelButtonStyle(con return cancelBlockStyle.release(); } +PassRefPtr<RenderStyle> RenderTextControlSingleLine::createOuterSpinButtonStyle() const +{ + ASSERT(node()->isHTMLElement()); + RefPtr<RenderStyle> buttonStyle = getCachedPseudoStyle(OUTER_SPIN_BUTTON); + if (!buttonStyle) + buttonStyle = RenderStyle::create(); + buttonStyle->inheritFrom(style()); + return buttonStyle.release(); +} + void RenderTextControlSingleLine::updateCancelButtonVisibility() const { if (!m_cancelButton->renderer()) diff --git a/WebCore/rendering/RenderTextControlSingleLine.h b/WebCore/rendering/RenderTextControlSingleLine.h index e1bcc84..b093954 100644 --- a/WebCore/rendering/RenderTextControlSingleLine.h +++ b/WebCore/rendering/RenderTextControlSingleLine.h @@ -32,6 +32,7 @@ class InputElement; class SearchFieldCancelButtonElement; class SearchFieldResultsButtonElement; class SearchPopupMenu; +class SpinButtonElement; class TextControlInnerElement; class RenderTextControlSingleLine : public RenderTextControl, private PopupMenuClient { @@ -53,12 +54,19 @@ public: void capsLockStateMayHaveChanged(); + // Decoration width outside of the text field. + int decorationWidthRight() const; + private: + int preferredDecorationWidthRight() const; virtual bool hasControlClip() const { return m_cancelButton; } + virtual IntRect controlClipRect(int tx, int ty) const; virtual bool isTextField() const { return true; } virtual void subtreeHasChanged(); virtual void paint(PaintInfo&, int tx, int ty); + virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); + virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); virtual void layout(); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); @@ -89,6 +97,7 @@ private: PassRefPtr<RenderStyle> createInnerBlockStyle(const RenderStyle* startStyle) const; PassRefPtr<RenderStyle> createResultsButtonStyle(const RenderStyle* startStyle) const; PassRefPtr<RenderStyle> createCancelButtonStyle(const RenderStyle* startStyle) const; + PassRefPtr<RenderStyle> createOuterSpinButtonStyle() const; void updateCancelButtonVisibility() const; EVisibility visibilityForCancelButton() const; @@ -130,6 +139,7 @@ private: RefPtr<TextControlInnerElement> m_innerBlock; RefPtr<SearchFieldResultsButtonElement> m_resultsButton; RefPtr<SearchFieldCancelButtonElement> m_cancelButton; + RefPtr<TextControlInnerElement> m_outerSpinButton; Timer<RenderTextControlSingleLine> m_searchEventTimer; RefPtr<SearchPopupMenu> m_searchPopup; diff --git a/WebCore/rendering/RenderTheme.cpp b/WebCore/rendering/RenderTheme.cpp index b3b7a1e..76af001 100644 --- a/WebCore/rendering/RenderTheme.cpp +++ b/WebCore/rendering/RenderTheme.cpp @@ -36,6 +36,7 @@ #include "RenderView.h" #include "SelectionController.h" #include "Settings.h" +#include "TextControlInnerElements.h" // The methods in this file are shared by all themes on every platform. @@ -617,6 +618,7 @@ bool RenderTheme::isControlStyled(const RenderStyle* style, const BorderData& bo case ButtonPart: case ListboxPart: case MenulistPart: + case ProgressBarPart: // FIXME: Uncomment this when making search fields style-able. // case SearchFieldPart: case TextFieldPart: @@ -660,10 +662,16 @@ bool RenderTheme::stateChanged(RenderObject* o, ControlState state) const ControlStates RenderTheme::controlStatesForRenderer(const RenderObject* o) const { ControlStates result = 0; - if (isHovered(o)) + if (isHovered(o)) { result |= HoverState; - if (isPressed(o)) + if (isSpinUpButtonPartHovered(o)) + result |= SpinUpState; + } + if (isPressed(o)) { result |= PressedState; + if (isSpinUpButtonPartPressed(o)) + result |= SpinUpState; + } if (isFocused(o) && o->style()->outlineStyleIsAuto()) result |= FocusState; if (isEnabled(o)) @@ -747,6 +755,16 @@ bool RenderTheme::isPressed(const RenderObject* o) const return o->node()->active(); } +bool RenderTheme::isSpinUpButtonPartPressed(const RenderObject* o) const +{ + Node* node = o->node(); + if (!node || !node->active() || !node->isElementNode() + || !static_cast<Element*>(node)->isSpinButtonElement()) + return false; + SpinButtonElement* element = static_cast<SpinButtonElement*>(node); + return element->onUpButton(); +} + bool RenderTheme::isReadOnlyControl(const RenderObject* o) const { Node* node = o->node(); @@ -762,6 +780,16 @@ bool RenderTheme::isHovered(const RenderObject* o) const return o->node()->hovered(); } +bool RenderTheme::isSpinUpButtonPartHovered(const RenderObject* o) const +{ + Node* node = o->node(); + if (!node || !node->active() || !node->isElementNode() + || !static_cast<Element*>(node)->isSpinButtonElement()) + return false; + SpinButtonElement* element = static_cast<SpinButtonElement*>(node); + return element->onUpButton(); +} + bool RenderTheme::isDefault(const RenderObject* o) const { // A button should only have the default appearance if the page is active diff --git a/WebCore/rendering/RenderTheme.h b/WebCore/rendering/RenderTheme.h index 1526138..6edc878 100644 --- a/WebCore/rendering/RenderTheme.h +++ b/WebCore/rendering/RenderTheme.h @@ -292,7 +292,9 @@ public: bool isEnabled(const RenderObject*) const; bool isFocused(const RenderObject*) const; bool isPressed(const RenderObject*) const; + bool isSpinUpButtonPartPressed(const RenderObject*) const; bool isHovered(const RenderObject*) const; + bool isSpinUpButtonPartHovered(const RenderObject*) const; bool isReadOnlyControl(const RenderObject*) const; bool isDefault(const RenderObject*) const; diff --git a/WebCore/rendering/RenderThemeChromiumMac.h b/WebCore/rendering/RenderThemeChromiumMac.h index 8101038..aaaade0 100644 --- a/WebCore/rendering/RenderThemeChromiumMac.h +++ b/WebCore/rendering/RenderThemeChromiumMac.h @@ -24,173 +24,32 @@ #ifndef RenderThemeChromiumMac_h #define RenderThemeChromiumMac_h -#import "RenderTheme.h" -#import <wtf/HashMap.h> -#import <wtf/RetainPtr.h> - -#ifdef __OBJC__ -@class WebCoreRenderThemeNotificationObserver; -#else -class WebCoreRenderThemeNotificationObserver; -#endif - -// This file (and its associated .mm file) is a clone of RenderThemeMac.h. See -// the .mm file for details. +#import "RenderThemeMac.h" namespace WebCore { -class RenderStyle; - -class RenderThemeChromiumMac : public RenderTheme { +class RenderThemeChromiumMac : public RenderThemeMac { public: 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; - - // A general method asking if any control tinting is supported at all. - virtual bool supportsControlTints() const { return true; } - - virtual void adjustRepaintRect(const RenderObject*, IntRect&); - - virtual bool isControlStyled(const RenderStyle*, const BorderData&, - const FillLayer&, const Color& backgroundColor) const; - - virtual Color platformActiveSelectionBackgroundColor() const; - virtual Color platformInactiveSelectionBackgroundColor() const; - virtual Color platformActiveListBoxSelectionBackgroundColor() const; - virtual Color platformActiveListBoxSelectionForegroundColor() const; - virtual Color platformInactiveListBoxSelectionBackgroundColor() const; - virtual Color platformInactiveListBoxSelectionForegroundColor() const; - virtual Color platformFocusRingColor() const; - - virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return SmallScrollbar; } - - virtual void platformColorsDidChange(); - - // System fonts. - virtual void systemFont(int cssValueId, FontDescription&) const; - - virtual int minimumMenuListSize(RenderStyle*) const; - - virtual void adjustSliderThumbSize(RenderObject*) const; - - virtual int popupInternalPaddingLeft(RenderStyle*) const; - virtual int popupInternalPaddingRight(RenderStyle*) const; - virtual int popupInternalPaddingTop(RenderStyle*) const; - virtual int popupInternalPaddingBottom(RenderStyle*) const; - - virtual bool paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - - virtual Color systemColor(int cssValueId) const; - protected: - virtual bool supportsSelectionForegroundColors() const { return false; } - - virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - - virtual bool paintTextArea(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - - virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - - virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - - virtual bool paintSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - virtual void adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - - virtual bool paintSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - virtual void adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - - virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - - virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldCancelButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - - virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - - virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldResultsDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - - virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldResultsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - #if ENABLE(VIDEO) - virtual bool shouldRenderMediaControlPart(ControlPart, Element*); + virtual void adjustMediaSliderThumbSize(RenderObject*) const; virtual bool paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaMuteButton(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 paintMediaVolumeSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - virtual bool paintMediaVolumeSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaControlsBackground(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - - // Media controls + virtual bool shouldRenderMediaControlPart(ControlPart, Element*); virtual String extraMediaControlsStyleSheet(); -#endif - -private: - RenderThemeChromiumMac(); - virtual ~RenderThemeChromiumMac(); - - IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const; - - FloatRect convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const; - - // Get the control size based off the font. Used by some of the controls (like buttons). - NSControlSize controlSizeForFont(RenderStyle*) const; - NSControlSize controlSizeForSystemFont(RenderStyle*) const; - void setControlSize(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel = 1.0f); - void setSizeFromFont(RenderStyle*, const IntSize* sizes) const; - IntSize sizeForFont(RenderStyle*, const IntSize* sizes) const; - IntSize sizeForSystemFont(RenderStyle*, const IntSize* sizes) const; - void setFontFromControlSize(CSSStyleSelector*, RenderStyle*, NSControlSize) const; - void updateActiveState(NSCell*, const RenderObject*); - void updateCheckedState(NSCell*, const RenderObject*); - void updateEnabledState(NSCell*, const RenderObject*); - void updateFocusedState(NSCell*, const RenderObject*); - void updatePressedState(NSCell*, const RenderObject*); - - // Helpers for adjusting appearance and for painting - - void setPopupButtonCellState(const RenderObject*, const IntRect&); - const IntSize* popupButtonSizes() const; - const int* popupButtonMargins() const; - const int* popupButtonPadding(NSControlSize) const; - void paintMenuListButtonGradients(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - const IntSize* menuListSizes() const; + virtual bool paintMediaVolumeSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaVolumeSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - const IntSize* searchFieldSizes() const; - const IntSize* cancelButtonSizes() const; - const IntSize* resultsButtonSizes() const; - void setSearchCellState(RenderObject*, const IntRect&); - void setSearchFieldSize(RenderStyle*) const; - - NSPopUpButtonCell* popupButton() const; - NSSearchFieldCell* search() const; - NSMenu* searchMenuTemplate() const; - NSSliderCell* sliderThumbHorizontal() const; - NSSliderCell* sliderThumbVertical() const; +#endif + virtual bool usesTestModeFocusRingColor() const; + virtual NSView* documentViewFor(RenderObject*) const; private: - mutable RetainPtr<NSPopUpButtonCell> m_popupButton; - mutable RetainPtr<NSSearchFieldCell> m_search; - mutable RetainPtr<NSMenu> m_searchMenuTemplate; - mutable RetainPtr<NSSliderCell> m_sliderThumbHorizontal; - mutable RetainPtr<NSSliderCell> m_sliderThumbVertical; - - bool m_isSliderThumbHorizontalPressed; - bool m_isSliderThumbVerticalPressed; - - mutable HashMap<int, RGBA32> m_systemColorCache; - - RetainPtr<WebCoreRenderThemeNotificationObserver> m_notificationObserver; + virtual void updateActiveState(NSCell*, const RenderObject*); }; } // namespace WebCore diff --git a/WebCore/rendering/RenderThemeChromiumMac.mm b/WebCore/rendering/RenderThemeChromiumMac.mm index 03aab1c..47a872d 100644 --- a/WebCore/rendering/RenderThemeChromiumMac.mm +++ b/WebCore/rendering/RenderThemeChromiumMac.mm @@ -20,29 +20,8 @@ #import "config.h" #import "RenderThemeChromiumMac.h" - -#import "BitmapImage.h" #import "ChromiumBridge.h" -#import "ColorMac.h" -#import "CSSStyleSelector.h" -#import "CSSValueKeywords.h" -#import "Document.h" -#import "Element.h" -#import "FrameView.h" -#import "GraphicsContext.h" -#import "HTMLInputElement.h" -#import "HTMLMediaElement.h" -#import "HTMLNames.h" -#import "Image.h" -#import "LocalCurrentGraphicsContext.h" -#import "MediaControlElements.h" -#import "RenderMedia.h" #import "RenderMediaControlsChromium.h" -#import "RenderSlider.h" -#import "RenderView.h" -#import "SharedBuffer.h" -#import "TimeRanges.h" -#import "WebCoreSystemInterface.h" #import "UserAgentStyleSheets.h" #import <Carbon/Carbon.h> #import <Cocoa/Cocoa.h> @@ -50,64 +29,6 @@ #import <wtf/StdLibExtras.h> #import <math.h> -#ifdef BUILDING_ON_TIGER -typedef int NSInteger; -typedef unsigned NSUInteger; -#endif - -using std::min; - -// This file (and its associated .h file) is a clone of RenderThemeMac.mm. -// Because the original file is designed to run in-process inside a Cocoa view, -// we must maintain a fork. Please maintain this file by performing parallel -// changes to it. -// -// The only changes from RenderThemeMac should be: -// - The classname change from RenderThemeMac to RenderThemeChromiumMac. -// - The introduction of RTCMFlippedView and FlippedView() and its use as the -// parent view for cell rendering. -// - In platformFocusRingColor(), the use of ChromiumBridge to determine if -// we're in layout test mode. -// - updateActiveState() and its use to update the cells' visual appearance. -// - All the paintMedia*() functions and extraMediaControlsStyleSheet() -// are forked from RenderThemeChromiumSkia instead of RenderThemeMac. -// -// For all other differences, if it was introduced in this file, then the -// maintainer forgot to include it in the list; otherwise it is an update that -// should have been applied to this file but was not. - -// The methods in this file are specific to the Mac OS X platform. - -// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari. - -@interface WebCoreRenderThemeNotificationObserver : NSObject -{ - WebCore::RenderTheme *_theme; -} - -- (id)initWithTheme:(WebCore::RenderTheme *)theme; -- (void)systemColorsDidChange:(NSNotification *)notification; - -@end - -@implementation WebCoreRenderThemeNotificationObserver - -- (id)initWithTheme:(WebCore::RenderTheme *)theme -{ - [super init]; - _theme = theme; - - return self; -} - -- (void)systemColorsDidChange:(NSNotification *)unusedNotification -{ - ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]); - _theme->platformColorsDidChange(); -} - -@end - @interface RTCMFlippedView : NSView {} @@ -130,26 +51,6 @@ using std::min; namespace WebCore { -using namespace HTMLNames; - -enum { - topMargin, - rightMargin, - bottomMargin, - leftMargin -}; - -enum { - topPadding, - rightPadding, - bottomPadding, - leftPadding -}; - -// In Snow Leopard, many cells only check to see if the view they're passed is -// flipped, and if a nil view is passed, neglect to check if the current -// graphics context is flipped. Thus we pass a sham view to them, one whose -// flipped state just reflects the state of the context. NSView* FlippedView() { static NSView* view = [[RTCMFlippedView alloc] init]; @@ -167,422 +68,14 @@ PassRefPtr<RenderTheme> RenderThemeChromiumMac::create() return adoptRef(new RenderThemeChromiumMac); } -RenderThemeChromiumMac::RenderThemeChromiumMac() - : m_isSliderThumbHorizontalPressed(false) - , m_isSliderThumbVerticalPressed(false) - , m_notificationObserver(AdoptNS, [[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this]) +bool RenderThemeChromiumMac::usesTestModeFocusRingColor() const { - [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get() - selector:@selector(systemColorsDidChange:) - name:NSSystemColorsDidChangeNotification - object:nil]; + return ChromiumBridge::layoutTestMode(); } -RenderThemeChromiumMac::~RenderThemeChromiumMac() +NSView* RenderThemeChromiumMac::documentViewFor(RenderObject*) const { - [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()]; -} - -Color RenderThemeChromiumMac::platformActiveSelectionBackgroundColor() const -{ - NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; - return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); -} - -Color RenderThemeChromiumMac::platformInactiveSelectionBackgroundColor() const -{ - NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; - return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); -} - -Color RenderThemeChromiumMac::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::platformActiveListBoxSelectionForegroundColor() const -{ - return Color::white; -} - -Color RenderThemeChromiumMac::platformInactiveListBoxSelectionForegroundColor() const -{ - return Color::black; -} - -Color RenderThemeChromiumMac::platformFocusRingColor() const -{ - if (ChromiumBridge::layoutTestMode()) - return oldAquaFocusRingColor(); - - return systemColor(CSSValueWebkitFocusRingColor); -} - -Color RenderThemeChromiumMac::platformInactiveListBoxSelectionBackgroundColor() const -{ - return platformInactiveSelectionBackgroundColor(); -} - -static FontWeight toFontWeight(NSInteger appKitFontWeight) -{ - ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15); - if (appKitFontWeight > 14) - appKitFontWeight = 14; - else if (appKitFontWeight < 1) - appKitFontWeight = 1; - - static FontWeight fontWeights[] = { - FontWeight100, - FontWeight100, - FontWeight200, - FontWeight300, - FontWeight400, - FontWeight500, - FontWeight600, - FontWeight600, - FontWeight700, - FontWeight800, - FontWeight800, - FontWeight900, - FontWeight900, - FontWeight900 - }; - return fontWeights[appKitFontWeight - 1]; -} - -void RenderThemeChromiumMac::systemFont(int cssValueId, FontDescription& fontDescription) const -{ - DEFINE_STATIC_LOCAL(FontDescription, systemFont, ()); - DEFINE_STATIC_LOCAL(FontDescription, smallSystemFont, ()); - DEFINE_STATIC_LOCAL(FontDescription, menuFont, ()); - DEFINE_STATIC_LOCAL(FontDescription, labelFont, ()); - DEFINE_STATIC_LOCAL(FontDescription, miniControlFont, ()); - DEFINE_STATIC_LOCAL(FontDescription, smallControlFont, ()); - DEFINE_STATIC_LOCAL(FontDescription, controlFont, ()); - - FontDescription* cachedDesc; - NSFont* font = nil; - switch (cssValueId) { - case CSSValueSmallCaption: - cachedDesc = &smallSystemFont; - if (!smallSystemFont.isAbsoluteSize()) - font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]; - break; - case CSSValueMenu: - cachedDesc = &menuFont; - if (!menuFont.isAbsoluteSize()) - font = [NSFont menuFontOfSize:[NSFont systemFontSize]]; - break; - case CSSValueStatusBar: - cachedDesc = &labelFont; - if (!labelFont.isAbsoluteSize()) - font = [NSFont labelFontOfSize:[NSFont labelFontSize]]; - break; - case CSSValueWebkitMiniControl: - cachedDesc = &miniControlFont; - if (!miniControlFont.isAbsoluteSize()) - font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]]; - break; - case CSSValueWebkitSmallControl: - cachedDesc = &smallControlFont; - if (!smallControlFont.isAbsoluteSize()) - font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]; - break; - case CSSValueWebkitControl: - cachedDesc = &controlFont; - if (!controlFont.isAbsoluteSize()) - font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; - break; - default: - cachedDesc = &systemFont; - if (!systemFont.isAbsoluteSize()) - font = [NSFont systemFontOfSize:[NSFont systemFontSize]]; - } - - if (font) { - NSFontManager *fontManager = [NSFontManager sharedFontManager]; - cachedDesc->setIsAbsoluteSize(true); - cachedDesc->setGenericFamily(FontDescription::NoFamily); - cachedDesc->firstFamily().setFamily([font familyName]); - cachedDesc->setSpecifiedSize([font pointSize]); - cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font])); - cachedDesc->setItalic([fontManager traitsOfFont:font] & NSItalicFontMask); - } - fontDescription = *cachedDesc; -} - -static RGBA32 convertNSColorToColor(NSColor *color) -{ - NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; - if (colorInColorSpace) { - static const double scaleFactor = nextafter(256.0, 0.0); - return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]), - static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]), - static_cast<int>(scaleFactor * [colorInColorSpace blueComponent])); - } - - // This conversion above can fail if the NSColor in question is an NSPatternColor - // (as many system colors are). These colors are actually a repeating pattern - // not just a solid color. To work around this we simply draw a 1x1 image of - // the color and use that pixel's color. It might be better to use an average of - // the colors in the pattern instead. - NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil - pixelsWide:1 - pixelsHigh:1 - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:4 - bitsPerPixel:32]; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]]; - NSEraseRect(NSMakeRect(0, 0, 1, 1)); - [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)]; - [NSGraphicsContext restoreGraphicsState]; - - NSUInteger pixel[4]; - [offscreenRep getPixel:pixel atX:0 y:0]; - - [offscreenRep release]; - - return makeRGB(pixel[0], pixel[1], pixel[2]); -} - -static RGBA32 menuBackgroundColor() -{ - NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil - pixelsWide:1 - pixelsHigh:1 - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:4 - bitsPerPixel:32]; - - CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]); - CGRect rect = CGRectMake(0, 0, 1, 1); - HIThemeMenuDrawInfo drawInfo; - drawInfo.version = 0; - drawInfo.menuType = kThemeMenuTypePopUp; - HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted); - - NSUInteger pixel[4]; - [offscreenRep getPixel:pixel atX:0 y:0]; - - [offscreenRep release]; - - return makeRGB(pixel[0], pixel[1], pixel[2]); -} - -void RenderThemeChromiumMac::platformColorsDidChange() -{ - m_systemColorCache.clear(); - RenderTheme::platformColorsDidChange(); -} - -Color RenderThemeChromiumMac::systemColor(int cssValueId) const -{ - if (m_systemColorCache.contains(cssValueId)) - return m_systemColorCache.get(cssValueId); - - Color color; - switch (cssValueId) { - case CSSValueActiveborder: - color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); - break; - case CSSValueActivecaption: - color = convertNSColorToColor([NSColor windowFrameTextColor]); - break; - case CSSValueAppworkspace: - color = convertNSColorToColor([NSColor headerColor]); - break; - case CSSValueBackground: - // Use theme independent default - break; - case CSSValueButtonface: - // We use this value instead of NSColor's controlColor to avoid website incompatibilities. - // We may want to change this to use the NSColor in future. - color = 0xFFC0C0C0; - break; - case CSSValueButtonhighlight: - color = convertNSColorToColor([NSColor controlHighlightColor]); - break; - case CSSValueButtonshadow: - color = convertNSColorToColor([NSColor controlShadowColor]); - break; - case CSSValueButtontext: - color = convertNSColorToColor([NSColor controlTextColor]); - break; - case CSSValueCaptiontext: - color = convertNSColorToColor([NSColor textColor]); - break; - case CSSValueGraytext: - color = convertNSColorToColor([NSColor disabledControlTextColor]); - break; - case CSSValueHighlight: - color = convertNSColorToColor([NSColor selectedTextBackgroundColor]); - break; - case CSSValueHighlighttext: - color = convertNSColorToColor([NSColor selectedTextColor]); - break; - case CSSValueInactiveborder: - color = convertNSColorToColor([NSColor controlBackgroundColor]); - break; - case CSSValueInactivecaption: - color = convertNSColorToColor([NSColor controlBackgroundColor]); - break; - case CSSValueInactivecaptiontext: - color = convertNSColorToColor([NSColor textColor]); - break; - case CSSValueInfobackground: - // There is no corresponding NSColor for this so we use a hard coded value. - color = 0xFFFBFCC5; - break; - case CSSValueInfotext: - color = convertNSColorToColor([NSColor textColor]); - break; - case CSSValueMenu: - color = menuBackgroundColor(); - break; - case CSSValueMenutext: - color = convertNSColorToColor([NSColor selectedMenuItemTextColor]); - break; - case CSSValueScrollbar: - color = convertNSColorToColor([NSColor scrollBarColor]); - break; - case CSSValueText: - color = convertNSColorToColor([NSColor textColor]); - break; - case CSSValueThreeddarkshadow: - color = convertNSColorToColor([NSColor controlDarkShadowColor]); - break; - case CSSValueThreedshadow: - color = convertNSColorToColor([NSColor shadowColor]); - break; - case CSSValueThreedface: - // We use this value instead of NSColor's controlColor to avoid website incompatibilities. - // We may want to change this to use the NSColor in future. - color = 0xFFC0C0C0; - break; - case CSSValueThreedhighlight: - color = convertNSColorToColor([NSColor highlightColor]); - break; - case CSSValueThreedlightshadow: - color = convertNSColorToColor([NSColor controlLightHighlightColor]); - break; - case CSSValueWebkitFocusRingColor: - color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); - break; - case CSSValueWindow: - color = convertNSColorToColor([NSColor windowBackgroundColor]); - break; - case CSSValueWindowframe: - color = convertNSColorToColor([NSColor windowFrameColor]); - break; - case CSSValueWindowtext: - color = convertNSColorToColor([NSColor windowFrameTextColor]); - break; - } - - if (!color.isValid()) - color = RenderTheme::systemColor(cssValueId); - - if (color.isValid()) - m_systemColorCache.set(cssValueId, color.rgb()); - - return color; -} - -bool RenderThemeChromiumMac::isControlStyled(const RenderStyle* style, const BorderData& border, - const FillLayer& background, const Color& backgroundColor) const -{ - if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart) - return style->border() != border; - - // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when - // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style - // adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming - // is in effect we treat it like the control is styled. - if (style->appearance() == MenulistPart && style->effectiveZoom() != 1.0f) - return true; - - return RenderTheme::isControlStyled(style, border, background, backgroundColor); -} - -void RenderThemeChromiumMac::adjustRepaintRect(const RenderObject* o, IntRect& r) -{ - ControlPart part = o->style()->appearance(); - -#if USE(NEW_THEME) - switch (part) { - case CheckboxPart: - case RadioPart: - case PushButtonPart: - case SquareButtonPart: - case ListButtonPart: - case DefaultButtonPart: - case ButtonPart: - return RenderTheme::adjustRepaintRect(o, r); - default: - break; - } -#endif - - float zoomLevel = o->style()->effectiveZoom(); - - if (part == MenulistPart) { - setPopupButtonCellState(o, r); - IntSize size = popupButtonSizes()[[popupButton() controlSize]]; - size.setHeight(size.height() * zoomLevel); - size.setWidth(r.width()); - r = inflateRect(r, size, popupButtonMargins(), zoomLevel); - } -} - -IntRect RenderThemeChromiumMac::inflateRect(const IntRect& r, const IntSize& size, const int* margins, float zoomLevel) const -{ - // Only do the inflation if the available width/height are too small. Otherwise try to - // fit the glow/check space into the available box's width/height. - int widthDelta = r.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel); - int heightDelta = r.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel); - IntRect result(r); - if (widthDelta < 0) { - result.setX(result.x() - margins[leftMargin] * zoomLevel); - result.setWidth(result.width() - widthDelta); - } - if (heightDelta < 0) { - result.setY(result.y() - margins[topMargin] * zoomLevel); - result.setHeight(result.height() - heightDelta); - } - return result; -} - -FloatRect RenderThemeChromiumMac::convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const -{ - FloatRect partRect(inputRect); - - // Compute an offset between the part renderer and the input renderer - FloatSize offsetFromInputRenderer; - const RenderObject* renderer = partRenderer; - while (renderer && renderer != inputRenderer) { - RenderObject* containingRenderer = renderer->container(); - offsetFromInputRenderer -= renderer->offsetFromContainer(containingRenderer, IntPoint()); - renderer = containingRenderer; - } - // If the input renderer was not a container, something went wrong - ASSERT(renderer == inputRenderer); - // Move the rect into partRenderer's coords - partRect.move(offsetFromInputRenderer); - // Account for the local drawing offset (tx, ty) - partRect.move(r.x(), r.y()); - - return partRect; + return FlippedView(); } // Updates the control tint (a.k.a. active state) of |cell| (from |o|). @@ -604,917 +97,13 @@ void RenderThemeChromiumMac::updateActiveState(NSCell* cell, const RenderObject* [cell setControlTint:tint]; } -void RenderThemeChromiumMac::updateCheckedState(NSCell* cell, const RenderObject* o) -{ - bool oldIndeterminate = [cell state] == NSMixedState; - bool indeterminate = isIndeterminate(o); - bool checked = isChecked(o); - - if (oldIndeterminate != indeterminate) { - [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)]; - return; - } - - bool oldChecked = [cell state] == NSOnState; - if (checked != oldChecked) - [cell setState:checked ? NSOnState : NSOffState]; -} - -void RenderThemeChromiumMac::updateEnabledState(NSCell* cell, const RenderObject* o) -{ - bool oldEnabled = [cell isEnabled]; - bool enabled = isEnabled(o); - if (enabled != oldEnabled) - [cell setEnabled:enabled]; -} - -void RenderThemeChromiumMac::updateFocusedState(NSCell* cell, const RenderObject* o) -{ - bool oldFocused = [cell showsFirstResponder]; - bool focused = isFocused(o) && o->style()->outlineStyleIsAuto(); - if (focused != oldFocused) - [cell setShowsFirstResponder:focused]; -} - -void RenderThemeChromiumMac::updatePressedState(NSCell* cell, const RenderObject* o) -{ - bool oldPressed = [cell isHighlighted]; - bool pressed = (o->node() && o->node()->active()); - if (pressed != oldPressed) - [cell setHighlighted:pressed]; -} - -bool RenderThemeChromiumMac::controlSupportsTints(const RenderObject* o) const -{ - // An alternate way to implement this would be to get the appropriate cell object - // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of - // that would be that we would match AppKit behavior more closely, but a disadvantage - // would be that we would rely on an AppKit SPI method. - - if (!isEnabled(o)) - return false; - - // Checkboxes only have tint when checked. - if (o->style()->appearance() == CheckboxPart) - return isChecked(o); - - // For now assume other controls have tint if enabled. - return true; -} - -NSControlSize RenderThemeChromiumMac::controlSizeForFont(RenderStyle* style) const -{ - int fontSize = style->fontSize(); - if (fontSize >= 16) - return NSRegularControlSize; - if (fontSize >= 11) - return NSSmallControlSize; - return NSMiniControlSize; -} - -void RenderThemeChromiumMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel) -{ - NSControlSize size; - if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel) && - minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel)) - size = NSRegularControlSize; - else if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel) && - minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel)) - size = NSSmallControlSize; - else - size = NSMiniControlSize; - if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same. - [cell setControlSize:size]; -} - -IntSize RenderThemeChromiumMac::sizeForFont(RenderStyle* style, const IntSize* sizes) const -{ - if (style->effectiveZoom() != 1.0f) { - IntSize result = sizes[controlSizeForFont(style)]; - return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom()); - } - return sizes[controlSizeForFont(style)]; -} - -IntSize RenderThemeChromiumMac::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const -{ - if (style->effectiveZoom() != 1.0f) { - IntSize result = sizes[controlSizeForSystemFont(style)]; - return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom()); - } - return sizes[controlSizeForSystemFont(style)]; -} - -void RenderThemeChromiumMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const -{ - // FIXME: Check is flawed, since it doesn't take min-width/max-width into account. - IntSize size = sizeForFont(style, sizes); - if (style->width().isIntrinsicOrAuto() && size.width() > 0) - style->setWidth(Length(size.width(), Fixed)); - if (style->height().isAuto() && size.height() > 0) - style->setHeight(Length(size.height(), Fixed)); -} - -void RenderThemeChromiumMac::setFontFromControlSize(CSSStyleSelector*, RenderStyle* style, NSControlSize controlSize) const -{ - FontDescription fontDescription; - fontDescription.setIsAbsoluteSize(true); - fontDescription.setGenericFamily(FontDescription::SerifFamily); - - NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]]; - fontDescription.firstFamily().setFamily([font familyName]); - fontDescription.setComputedSize([font pointSize] * style->effectiveZoom()); - fontDescription.setSpecifiedSize([font pointSize] * style->effectiveZoom()); - - // Reset line height - style->setLineHeight(RenderStyle::initialLineHeight()); - - if (style->setFontDescription(fontDescription)) - style->font().update(0); -} - -NSControlSize RenderThemeChromiumMac::controlSizeForSystemFont(RenderStyle* style) const -{ - int fontSize = style->fontSize(); - if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize]) - return NSRegularControlSize; - if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize]) - return NSSmallControlSize; - return NSMiniControlSize; -} - -bool RenderThemeChromiumMac::paintTextField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) -{ - LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawBezeledTextFieldCell(r, isEnabled(o) && !isReadOnlyControl(o)); - return false; -} - -void RenderThemeChromiumMac::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const -{ -} - -bool RenderThemeChromiumMac::paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo& paintInfo, const IntRect& r) -{ - if (paintInfo.context->paintingDisabled()) - return true; - - LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawCapsLockIndicator(paintInfo.context->platformContext(), r); - - return false; -} - -bool RenderThemeChromiumMac::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) -{ - LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawBezeledTextArea(r, isEnabled(o) && !isReadOnlyControl(o)); - return false; -} - -void RenderThemeChromiumMac::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const -{ -} - -const int* RenderThemeChromiumMac::popupButtonMargins() const -{ - static const int margins[3][4] = - { - { 0, 3, 1, 3 }, - { 0, 3, 2, 3 }, - { 0, 1, 0, 1 } - }; - return margins[[popupButton() controlSize]]; -} - -const IntSize* RenderThemeChromiumMac::popupButtonSizes() const -{ - static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; - return sizes; -} - -const int* RenderThemeChromiumMac::popupButtonPadding(NSControlSize size) const -{ - static const int padding[3][4] = - { - { 2, 26, 3, 8 }, - { 2, 23, 3, 8 }, - { 2, 22, 3, 10 } - }; - return padding[size]; -} - -bool RenderThemeChromiumMac::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) -{ - setPopupButtonCellState(o, r); - - NSPopUpButtonCell* popupButton = this->popupButton(); - - float zoomLevel = o->style()->effectiveZoom(); - IntSize size = popupButtonSizes()[[popupButton controlSize]]; - size.setHeight(size.height() * zoomLevel); - size.setWidth(r.width()); - - // Now inflate it to account for the shadow. - IntRect inflatedRect = r; - if (r.width() >= minimumMenuListSize(o->style())) - inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel); - - paintInfo.context->save(); - -#ifndef BUILDING_ON_TIGER - // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect - paintInfo.context->clip(inflatedRect); -#endif - - if (zoomLevel != 1.0f) { - inflatedRect.setWidth(inflatedRect.width() / zoomLevel); - inflatedRect.setHeight(inflatedRect.height() / zoomLevel); - paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); - paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); - } - - [popupButton drawWithFrame:inflatedRect inView:FlippedView()]; - [popupButton setControlView:nil]; - - paintInfo.context->restore(); - - return false; -} - -const float baseFontSize = 11.0f; -const float baseArrowHeight = 4.0f; -const float baseArrowWidth = 5.0f; -const float baseSpaceBetweenArrows = 2.0f; -const int arrowPaddingLeft = 6; -const int arrowPaddingRight = 6; -const int paddingBeforeSeparator = 4; -const int baseBorderRadius = 5; -const int styledPopupPaddingLeft = 8; -const int styledPopupPaddingTop = 1; -const int styledPopupPaddingBottom = 2; - -static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) -{ - static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f }; - static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f }; - float a = inData[0]; - int i = 0; - for (i = 0; i < 4; i++) - outData[i] = (1.0f - a) * dark[i] + a * light[i]; -} - -static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) -{ - static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f }; - static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f }; - float a = inData[0]; - int i = 0; - for (i = 0; i < 4; i++) - outData[i] = (1.0f - a) * dark[i] + a * light[i]; -} - -static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) -{ - static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f }; - static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - float a = inData[0]; - int i = 0; - for (i = 0; i < 4; i++) - outData[i] = (1.0f - a) * dark[i] + a * light[i]; -} - -static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) -{ - static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f }; - static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f }; - float a = inData[0]; - int i = 0; - for (i = 0; i < 4; i++) - outData[i] = (1.0f - a) * dark[i] + a * light[i]; -} - -void RenderThemeChromiumMac::paintMenuListButtonGradients(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) -{ - if (r.isEmpty()) - return; - - CGContextRef context = paintInfo.context->platformContext(); - - paintInfo.context->save(); - - IntSize topLeftRadius; - IntSize topRightRadius; - IntSize bottomLeftRadius; - IntSize bottomRightRadius; - - o->style()->getBorderRadiiForRect(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); - - int radius = topLeftRadius.width(); - - RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB()); - - FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f); - struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL }; - RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks)); - RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.bottom()), topFunction.get(), false, false)); - - FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f); - struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL }; - RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks)); - RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.bottom()), bottomFunction.get(), false, false)); - - struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL }; - RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); - RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.bottom()), mainFunction.get(), false, false)); - - RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false)); - - RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.right(), r.y()), CGPointMake(r.right() - radius, r.y()), mainFunction.get(), false, false)); - paintInfo.context->save(); - CGContextClipToRect(context, r); - paintInfo.context->addRoundedRectClip(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); - CGContextDrawShading(context, mainShading.get()); - paintInfo.context->restore(); - - paintInfo.context->save(); - CGContextClipToRect(context, topGradient); - paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient), topLeftRadius, topRightRadius, IntSize(), IntSize()); - CGContextDrawShading(context, topShading.get()); - paintInfo.context->restore(); - - if (!bottomGradient.isEmpty()) { - paintInfo.context->save(); - CGContextClipToRect(context, bottomGradient); - paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient), IntSize(), IntSize(), bottomLeftRadius, bottomRightRadius); - CGContextDrawShading(context, bottomShading.get()); - paintInfo.context->restore(); - } - - paintInfo.context->save(); - CGContextClipToRect(context, r); - paintInfo.context->addRoundedRectClip(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); - CGContextDrawShading(context, leftShading.get()); - CGContextDrawShading(context, rightShading.get()); - paintInfo.context->restore(); - - paintInfo.context->restore(); -} - -bool RenderThemeChromiumMac::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) -{ - IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(), - r.y() + o->style()->borderTopWidth(), - r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(), - r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth()); - // Draw the gradients to give the styled popup menu a button appearance - paintMenuListButtonGradients(o, paintInfo, bounds); - - // Since we actually know the size of the control here, we restrict the font scale to make sure the arrows will fit vertically in the bounds - float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows)); - float centerY = bounds.y() + bounds.height() / 2.0f; - float arrowHeight = baseArrowHeight * fontScale; - float arrowWidth = baseArrowWidth * fontScale; - float leftEdge = bounds.right() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth; - float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale; - - if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom()) - return false; - - paintInfo.context->save(); - - paintInfo.context->setFillColor(o->style()->color(), o->style()->colorSpace()); - paintInfo.context->setStrokeStyle(NoStroke); - - FloatPoint arrow1[3]; - arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f); - arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f); - arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight); - - // Draw the top arrow - paintInfo.context->drawConvexPolygon(3, arrow1, true); - - FloatPoint arrow2[3]; - arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f); - arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f); - arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight); - - // Draw the bottom arrow - paintInfo.context->drawConvexPolygon(3, arrow2, true); - - Color leftSeparatorColor(0, 0, 0, 40); - Color rightSeparatorColor(255, 255, 255, 40); - - // FIXME: Should the separator thickness and space be scaled up by fontScale? - int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin. - int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * o->style()->effectiveZoom()); // FIXME: Round? - - // Draw the separator to the left of the arrows - paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin. - paintInfo.context->setStrokeStyle(SolidStroke); - paintInfo.context->setStrokeColor(leftSeparatorColor, DeviceColorSpace); - paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()), - IntPoint(leftEdgeOfSeparator, bounds.bottom())); - - paintInfo.context->setStrokeColor(rightSeparatorColor, DeviceColorSpace); - paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()), - IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom())); - - paintInfo.context->restore(); - return false; -} - -static const IntSize* menuListButtonSizes() -{ - static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; - return sizes; -} - -void RenderThemeChromiumMac::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const -{ - NSControlSize controlSize = controlSizeForFont(style); - - style->resetBorder(); - style->resetPadding(); - - // Height is locked to auto. - style->setHeight(Length(Auto)); - - // White-space is locked to pre - style->setWhiteSpace(PRE); - - // Set the foreground color to black or gray when we have the aqua look. - // Cast to RGB32 is to work around a compiler bug. - style->setColor(e && e->isEnabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray); - - // Set the button's vertical size. - setSizeFromFont(style, menuListButtonSizes()); - - // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out - // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate - // system font for the control size instead. - setFontFromControlSize(selector, style, controlSize); - - style->setBoxShadow(0); -} - -int RenderThemeChromiumMac::popupInternalPaddingLeft(RenderStyle* style) const -{ - if (style->appearance() == MenulistPart) - return popupButtonPadding(controlSizeForFont(style))[leftPadding] * style->effectiveZoom(); - if (style->appearance() == MenulistButtonPart) - return styledPopupPaddingLeft * style->effectiveZoom(); - return 0; -} - -int RenderThemeChromiumMac::popupInternalPaddingRight(RenderStyle* style) const -{ - if (style->appearance() == MenulistPart) - return popupButtonPadding(controlSizeForFont(style))[rightPadding] * style->effectiveZoom(); - if (style->appearance() == MenulistButtonPart) { - float fontScale = style->fontSize() / baseFontSize; - float arrowWidth = baseArrowWidth * fontScale; - return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom())); - } - return 0; -} - -int RenderThemeChromiumMac::popupInternalPaddingTop(RenderStyle* style) const -{ - if (style->appearance() == MenulistPart) - return popupButtonPadding(controlSizeForFont(style))[topPadding] * style->effectiveZoom(); - if (style->appearance() == MenulistButtonPart) - return styledPopupPaddingTop * style->effectiveZoom(); - return 0; -} - -int RenderThemeChromiumMac::popupInternalPaddingBottom(RenderStyle* style) const -{ - if (style->appearance() == MenulistPart) - return popupButtonPadding(controlSizeForFont(style))[bottomPadding] * style->effectiveZoom(); - if (style->appearance() == MenulistButtonPart) - return styledPopupPaddingBottom * style->effectiveZoom(); - return 0; -} - -void RenderThemeChromiumMac::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - float fontScale = style->fontSize() / baseFontSize; - - style->resetPadding(); - style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up? - - const int minHeight = 15; - style->setMinHeight(Length(minHeight, Fixed)); - - style->setLineHeight(RenderStyle::initialLineHeight()); -} - -void RenderThemeChromiumMac::setPopupButtonCellState(const RenderObject* o, const IntRect& r) -{ - NSPopUpButtonCell* popupButton = this->popupButton(); - - // Set the control size based off the rectangle we're painting into. - setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom()); - - // Update the various states we respond to. - updateActiveState(popupButton, o); - updateCheckedState(popupButton, o); - updateEnabledState(popupButton, o); - updatePressedState(popupButton, o); - updateFocusedState(popupButton, o); -} - -const IntSize* RenderThemeChromiumMac::menuListSizes() const -{ - static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) }; - return sizes; -} - -int RenderThemeChromiumMac::minimumMenuListSize(RenderStyle* style) const -{ - return sizeForSystemFont(style, menuListSizes()).width(); -} - -const int trackWidth = 5; -const int trackRadius = 2; - -void RenderThemeChromiumMac::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - style->setBoxShadow(0); -} - -bool RenderThemeChromiumMac::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) -{ - IntRect bounds = r; - float zoomLevel = o->style()->effectiveZoom(); - float zoomedTrackWidth = trackWidth * zoomLevel; - - if (o->style()->appearance() == SliderHorizontalPart || o->style()->appearance() == MediaSliderPart) { - bounds.setHeight(zoomedTrackWidth); - bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2); - } else if (o->style()->appearance() == SliderVerticalPart) { - bounds.setWidth(zoomedTrackWidth); - bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2); - } - - LocalCurrentGraphicsContext localContext(paintInfo.context); - CGContextRef context = paintInfo.context->platformContext(); - RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB()); - - paintInfo.context->save(); - CGContextClipToRect(context, bounds); - - struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL }; - RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); - RetainPtr<CGShadingRef> mainShading; - if (o->style()->appearance() == SliderVerticalPart) - mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(), bounds.bottom()), CGPointMake(bounds.right(), bounds.bottom()), mainFunction.get(), false, false)); - else - mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.bottom()), mainFunction.get(), false, false)); - - IntSize radius(trackRadius, trackRadius); - paintInfo.context->addRoundedRectClip(bounds, - radius, radius, - radius, radius); - CGContextDrawShading(context, mainShading.get()); - paintInfo.context->restore(); - - return false; -} - -void RenderThemeChromiumMac::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - style->setBoxShadow(0); -} - -const float verticalSliderHeightPadding = 0.1f; - -bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) -{ - ASSERT(o->parent()->isSlider()); - - NSSliderCell* sliderThumbCell = o->style()->appearance() == SliderThumbVerticalPart - ? sliderThumbVertical() - : sliderThumbHorizontal(); - - LocalCurrentGraphicsContext localContext(paintInfo.context); - - // Update the various states we respond to. - updateActiveState(sliderThumbCell, o->parent()); - updateEnabledState(sliderThumbCell, o->parent()); - updateFocusedState(sliderThumbCell, o->parent()); - - // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it. - bool oldPressed; - if (o->style()->appearance() == SliderThumbVerticalPart) - oldPressed = m_isSliderThumbVerticalPressed; - else - oldPressed = m_isSliderThumbHorizontalPressed; - - bool pressed = toRenderSlider(o->parent())->inDragMode(); - - if (o->style()->appearance() == SliderThumbVerticalPart) - m_isSliderThumbVerticalPressed = pressed; - else - m_isSliderThumbHorizontalPressed = pressed; - - if (pressed != oldPressed) { - if (pressed) - [sliderThumbCell startTrackingAt:NSPoint() inView:nil]; - else - [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES]; - } - - FloatRect bounds = r; - // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider. - if (o->style()->appearance() == SliderThumbVerticalPart) - bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o->style()->effectiveZoom()); - - paintInfo.context->save(); - float zoomLevel = o->style()->effectiveZoom(); - - FloatRect unzoomedRect = bounds; - if (zoomLevel != 1.0f) { - unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); - unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); - paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); - paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); - } - - [sliderThumbCell drawWithFrame:unzoomedRect inView:FlippedView()]; - [sliderThumbCell setControlView:nil]; - - paintInfo.context->restore(); - - return false; -} - -bool RenderThemeChromiumMac::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) -{ - NSSearchFieldCell* search = this->search(); - LocalCurrentGraphicsContext localContext(paintInfo.context); - - setSearchCellState(o, r); - - paintInfo.context->save(); - - float zoomLevel = o->style()->effectiveZoom(); - - IntRect unzoomedRect = r; - - if (zoomLevel != 1.0f) { - unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); - unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); - paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); - paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); - } - - // Set the search button to nil before drawing. Then reset it so we can draw it later. - [search setSearchButtonCell:nil]; - - [search drawWithFrame:NSRect(unzoomedRect) inView:FlippedView()]; -#ifdef BUILDING_ON_TIGER - if ([search showsFirstResponder]) - wkDrawTextFieldCellFocusRing(search, NSRect(unzoomedRect)); -#endif - - [search setControlView:nil]; - [search resetSearchButtonCell]; - - paintInfo.context->restore(); - - return false; -} - -void RenderThemeChromiumMac::setSearchCellState(RenderObject* o, const IntRect&) -{ - NSSearchFieldCell* search = this->search(); - - [search setControlSize:controlSizeForFont(o->style())]; - - // Update the various states we respond to. - updateActiveState(search, o); - updateEnabledState(search, o); - updateFocusedState(search, o); -} - -const IntSize* RenderThemeChromiumMac::searchFieldSizes() const -{ - static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) }; - return sizes; -} - -void RenderThemeChromiumMac::setSearchFieldSize(RenderStyle* style) const -{ - // If the width and height are both specified, then we have nothing to do. - if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) - return; - - // Use the font size to determine the intrinsic width of the control. - setSizeFromFont(style, searchFieldSizes()); -} - -void RenderThemeChromiumMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element*) const -{ - // Override border. - style->resetBorder(); - const short borderWidth = 2 * style->effectiveZoom(); - style->setBorderLeftWidth(borderWidth); - style->setBorderLeftStyle(INSET); - style->setBorderRightWidth(borderWidth); - style->setBorderRightStyle(INSET); - style->setBorderBottomWidth(borderWidth); - style->setBorderBottomStyle(INSET); - style->setBorderTopWidth(borderWidth); - style->setBorderTopStyle(INSET); - - // Override height. - style->setHeight(Length(Auto)); - setSearchFieldSize(style); - - // Override padding size to match AppKit text positioning. - const int padding = 1 * style->effectiveZoom(); - style->setPaddingLeft(Length(padding, Fixed)); - style->setPaddingRight(Length(padding, Fixed)); - style->setPaddingTop(Length(padding, Fixed)); - style->setPaddingBottom(Length(padding, Fixed)); - - NSControlSize controlSize = controlSizeForFont(style); - setFontFromControlSize(selector, style, controlSize); - - style->setBoxShadow(0); -} - -bool RenderThemeChromiumMac::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) -{ - Node* input = o->node()->shadowAncestorNode(); - if (!input->renderer()->isBox()) - return false; - - setSearchCellState(input->renderer(), r); - - NSSearchFieldCell* search = this->search(); - - updateActiveState([search cancelButtonCell], o); - updatePressedState([search cancelButtonCell], o); - - paintInfo.context->save(); - - float zoomLevel = o->style()->effectiveZoom(); - - FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())]; - localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); - - FloatRect unzoomedRect(localBounds); - if (zoomLevel != 1.0f) { - unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); - unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); - paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); - paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); - } - - [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:FlippedView()]; - [[search cancelButtonCell] setControlView:nil]; - - paintInfo.context->restore(); - return false; -} - -const IntSize* RenderThemeChromiumMac::cancelButtonSizes() const -{ - static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) }; - return sizes; -} - -void RenderThemeChromiumMac::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - IntSize size = sizeForSystemFont(style, cancelButtonSizes()); - style->setWidth(Length(size.width(), Fixed)); - style->setHeight(Length(size.height(), Fixed)); - style->setBoxShadow(0); -} - -const IntSize* RenderThemeChromiumMac::resultsButtonSizes() const -{ - static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) }; - return sizes; -} - -const int emptyResultsOffset = 9; -void RenderThemeChromiumMac::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - IntSize size = sizeForSystemFont(style, resultsButtonSizes()); - style->setWidth(Length(size.width() - emptyResultsOffset, Fixed)); - style->setHeight(Length(size.height(), Fixed)); - style->setBoxShadow(0); -} - -bool RenderThemeChromiumMac::paintSearchFieldDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) -{ - return false; -} - -void RenderThemeChromiumMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - IntSize size = sizeForSystemFont(style, resultsButtonSizes()); - style->setWidth(Length(size.width(), Fixed)); - style->setHeight(Length(size.height(), Fixed)); - style->setBoxShadow(0); -} - -bool RenderThemeChromiumMac::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) -{ - Node* input = o->node()->shadowAncestorNode(); - if (!input->renderer()->isBox()) - return false; - - setSearchCellState(input->renderer(), r); - - NSSearchFieldCell* search = this->search(); - - updateActiveState([search searchButtonCell], o); - - if ([search searchMenuTemplate] != nil) - [search setSearchMenuTemplate:nil]; - - FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())]; - localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); - - [[search searchButtonCell] drawWithFrame:localBounds inView:FlippedView()]; - [[search searchButtonCell] setControlView:nil]; - return false; -} - -const int resultsArrowWidth = 5; -void RenderThemeChromiumMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - IntSize size = sizeForSystemFont(style, resultsButtonSizes()); - style->setWidth(Length(size.width() + resultsArrowWidth, Fixed)); - style->setHeight(Length(size.height(), Fixed)); - style->setBoxShadow(0); -} - -bool RenderThemeChromiumMac::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) -{ - Node* input = o->node()->shadowAncestorNode(); - if (!input->renderer()->isBox()) - return false; - - setSearchCellState(input->renderer(), r); - - NSSearchFieldCell* search = this->search(); - - updateActiveState([search searchButtonCell], o); - - if (![search searchMenuTemplate]) - [search setSearchMenuTemplate:searchMenuTemplate()]; - - paintInfo.context->save(); - - float zoomLevel = o->style()->effectiveZoom(); - - FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())]; - localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); - - IntRect unzoomedRect(localBounds); - if (zoomLevel != 1.0f) { - unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); - unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); - paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); - paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); - } - - [[search searchButtonCell] drawWithFrame:unzoomedRect inView:FlippedView()]; - [[search searchButtonCell] setControlView:nil]; - - paintInfo.context->restore(); - - return false; -} - -const int sliderThumbWidth = 15; -const int sliderThumbHeight = 15; +#if ENABLE(VIDEO) -void RenderThemeChromiumMac::adjustSliderThumbSize(RenderObject* o) const +void RenderThemeChromiumMac::adjustMediaSliderThumbSize(RenderObject* o) const { - float zoomLevel = o->style()->effectiveZoom(); - if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == SliderThumbVerticalPart) { - o->style()->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed)); - o->style()->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed)); - } - -#if ENABLE(VIDEO) RenderMediaControlsChromium::adjustMediaSliderThumbSize(o); -#endif } -#if ENABLE(VIDEO) bool RenderThemeChromiumMac::shouldRenderMediaControlPart(ControlPart part, Element* e) { return RenderMediaControlsChromium::shouldRenderMediaControlPart(part, e); @@ -1535,21 +124,6 @@ bool RenderThemeChromiumMac::paintMediaSliderTrack(RenderObject* object, const R return RenderMediaControlsChromium::paintMediaControlsPart(MediaSlider, object, paintInfo, rect); } -bool RenderThemeChromiumMac::paintMediaVolumeSliderTrack(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) -{ - return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSlider, object, paintInfo, rect); -} - -bool RenderThemeChromiumMac::paintMediaSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) -{ - return RenderMediaControlsChromium::paintMediaControlsPart(MediaSliderThumb, object, paintInfo, rect); -} - -bool RenderThemeChromiumMac::paintMediaVolumeSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) -{ - return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSliderThumb, object, paintInfo, rect); -} - bool RenderThemeChromiumMac::paintMediaControlsBackground(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) { return RenderMediaControlsChromium::paintMediaControlsPart(MediaTimelineContainer, object, paintInfo, rect); @@ -1560,64 +134,16 @@ String RenderThemeChromiumMac::extraMediaControlsStyleSheet() return String(mediaControlsChromiumUserAgentStyleSheet, sizeof(mediaControlsChromiumUserAgentStyleSheet)); } -#endif - -NSPopUpButtonCell* RenderThemeChromiumMac::popupButton() const -{ - if (!m_popupButton) { - m_popupButton.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]); - [m_popupButton.get() setUsesItemFromMenu:NO]; - [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior]; - } - - return m_popupButton.get(); -} - -NSSearchFieldCell* RenderThemeChromiumMac::search() const -{ - if (!m_search) { - m_search.adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]); - [m_search.get() setBezelStyle:NSTextFieldRoundedBezel]; - [m_search.get() setBezeled:YES]; - [m_search.get() setEditable:YES]; - [m_search.get() setFocusRingType:NSFocusRingTypeExterior]; - } - - return m_search.get(); -} - -NSMenu* RenderThemeChromiumMac::searchMenuTemplate() const +bool RenderThemeChromiumMac::paintMediaVolumeSliderTrack(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) { - if (!m_searchMenuTemplate) - m_searchMenuTemplate.adoptNS([[NSMenu alloc] initWithTitle:@""]); - - return m_searchMenuTemplate.get(); + return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSlider, object, paintInfo, rect); } -NSSliderCell* RenderThemeChromiumMac::sliderThumbHorizontal() const +bool RenderThemeChromiumMac::paintMediaVolumeSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) { - if (!m_sliderThumbHorizontal) { - m_sliderThumbHorizontal.adoptNS([[NSSliderCell alloc] init]); - [m_sliderThumbHorizontal.get() setTitle:nil]; - [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider]; - [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize]; - [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior]; - } - - return m_sliderThumbHorizontal.get(); + return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSliderThumb, object, paintInfo, rect); } -NSSliderCell* RenderThemeChromiumMac::sliderThumbVertical() const -{ - if (!m_sliderThumbVertical) { - m_sliderThumbVertical.adoptNS([[NSSliderCell alloc] init]); - [m_sliderThumbVertical.get() setTitle:nil]; - [m_sliderThumbVertical.get() setSliderType:NSLinearSlider]; - [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize]; - [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior]; - } - - return m_sliderThumbVertical.get(); -} +#endif } // namespace WebCore diff --git a/WebCore/rendering/RenderThemeMac.h b/WebCore/rendering/RenderThemeMac.h index cba927f..cb604b9 100644 --- a/WebCore/rendering/RenderThemeMac.h +++ b/WebCore/rendering/RenderThemeMac.h @@ -88,8 +88,14 @@ public: #endif virtual Color systemColor(int cssValueId) const; - + // Controls color values returned from platformFocusRingColor(). systemColor() will be used when false. + virtual bool usesTestModeFocusRingColor() const; + // A view associated to the contained document. Subclasses may not have such a view and return a fake. + virtual NSView* documentViewFor(RenderObject*) const; protected: + RenderThemeMac(); + virtual ~RenderThemeMac(); + virtual bool supportsSelectionForegroundColors() const { return false; } virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); @@ -149,11 +155,10 @@ protected: virtual String extraMediaControlsStyleSheet(); virtual bool shouldRenderMediaControlPart(ControlPart, Element*); + virtual void adjustMediaSliderThumbSize(RenderObject*) const; #endif private: - RenderThemeMac(); - virtual ~RenderThemeMac(); IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const; @@ -172,6 +177,8 @@ private: void updateEnabledState(NSCell*, const RenderObject*); void updateFocusedState(NSCell*, const RenderObject*); void updatePressedState(NSCell*, const RenderObject*); + // An optional hook for subclasses to update the control tint of NSCell. + virtual void updateActiveState(NSCell*, const RenderObject*) {} // Helpers for adjusting appearance and for painting diff --git a/WebCore/rendering/RenderThemeMac.mm b/WebCore/rendering/RenderThemeMac.mm index c0d8020..d1a3965 100644 --- a/WebCore/rendering/RenderThemeMac.mm +++ b/WebCore/rendering/RenderThemeMac.mm @@ -115,11 +115,13 @@ enum { leftPadding }; +#if PLATFORM(MAC) PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*) { static RenderTheme* rt = RenderThemeMac::create().releaseRef(); return rt; } +#endif PassRefPtr<RenderTheme> RenderThemeMac::create() { @@ -458,6 +460,21 @@ Color RenderThemeMac::systemColor(int cssValueId) const return color; } +bool RenderThemeMac::usesTestModeFocusRingColor() const +{ + return WebCore::usesTestModeFocusRingColor(); +} + +NSView* RenderThemeMac::documentViewFor(RenderObject* o) const +{ +#if PLATFORM(MAC) + return ThemeMac::ensuredView(o->view()->frameView()); +#else + ASSERT_NOT_REACHED(); + return 0; +#endif +} + bool RenderThemeMac::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& background, const Color& backgroundColor) const { @@ -487,6 +504,7 @@ void RenderThemeMac::adjustRepaintRect(const RenderObject* o, IntRect& r) case ListButtonPart: case DefaultButtonPart: case ButtonPart: + case OuterSpinButtonPart: return RenderTheme::adjustRepaintRect(o, r); default: break; @@ -776,7 +794,7 @@ bool RenderThemeMac::paintMenuList(RenderObject* o, const RenderObject::PaintInf paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); } - [popupButton drawWithFrame:inflatedRect inView:ThemeMac::ensuredView(o->view()->frameView())]; + [popupButton drawWithFrame:inflatedRect inView:documentViewFor(o)]; [popupButton setControlView:nil]; paintInfo.context->restore(); @@ -1111,6 +1129,7 @@ void RenderThemeMac::setPopupButtonCellState(const RenderObject* o, const IntRec setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom()); // Update the various states we respond to. + updateActiveState(popupButton, o); updateCheckedState(popupButton, o); updateEnabledState(popupButton, o); updatePressedState(popupButton, o); @@ -1193,6 +1212,7 @@ bool RenderThemeMac::paintSliderThumb(RenderObject* o, const RenderObject::Paint LocalCurrentGraphicsContext localContext(paintInfo.context); // Update the various states we respond to. + updateActiveState(sliderThumbCell, o->parent()); updateEnabledState(sliderThumbCell, o->parent()); updateFocusedState(sliderThumbCell, o->parent()); @@ -1234,7 +1254,7 @@ bool RenderThemeMac::paintSliderThumb(RenderObject* o, const RenderObject::Paint paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } - [sliderThumbCell drawWithFrame:unzoomedRect inView:ThemeMac::ensuredView(o->view()->frameView())]; + [sliderThumbCell drawWithFrame:unzoomedRect inView:documentViewFor(o)]; [sliderThumbCell setControlView:nil]; paintInfo.context->restore(); @@ -1266,7 +1286,7 @@ bool RenderThemeMac::paintSearchField(RenderObject* o, const RenderObject::Paint // Set the search button to nil before drawing. Then reset it so we can draw it later. [search setSearchButtonCell:nil]; - [search drawWithFrame:NSRect(unzoomedRect) inView:ThemeMac::ensuredView(o->view()->frameView())]; + [search drawWithFrame:NSRect(unzoomedRect) inView:documentViewFor(o)]; #ifdef BUILDING_ON_TIGER if ([search showsFirstResponder]) wkDrawTextFieldCellFocusRing(search, NSRect(unzoomedRect)); @@ -1287,6 +1307,7 @@ void RenderThemeMac::setSearchCellState(RenderObject* o, const IntRect&) [search setControlSize:controlSizeForFont(o->style())]; // Update the various states we respond to. + updateActiveState(search, o); updateEnabledState(search, o); updateFocusedState(search, o); } @@ -1348,6 +1369,7 @@ bool RenderThemeMac::paintSearchFieldCancelButton(RenderObject* o, const RenderO NSSearchFieldCell* search = this->search(); + updateActiveState([search cancelButtonCell], o); updatePressedState([search cancelButtonCell], o); paintInfo.context->save(); @@ -1366,7 +1388,7 @@ bool RenderThemeMac::paintSearchFieldCancelButton(RenderObject* o, const RenderO paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } - [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:ThemeMac::ensuredView(o->view()->frameView())]; + [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)]; [[search cancelButtonCell] setControlView:nil]; paintInfo.context->restore(); @@ -1428,10 +1450,12 @@ bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const Re if ([search searchMenuTemplate] != nil) [search setSearchMenuTemplate:nil]; + updateActiveState([search searchButtonCell], o); + FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())]; localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); - [[search searchButtonCell] drawWithFrame:localBounds inView:ThemeMac::ensuredView(o->view()->frameView())]; + [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(o)]; [[search searchButtonCell] setControlView:nil]; return false; } @@ -1455,6 +1479,8 @@ bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const Render NSSearchFieldCell* search = this->search(); + updateActiveState([search searchButtonCell], o); + if (![search searchMenuTemplate]) [search setSearchMenuTemplate:searchMenuTemplate()]; @@ -1474,7 +1500,7 @@ bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const Render paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } - [[search searchButtonCell] drawWithFrame:unzoomedRect inView:ThemeMac::ensuredView(o->view()->frameView())]; + [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)]; [[search searchButtonCell] setControlView:nil]; paintInfo.context->restore(); @@ -1527,7 +1553,15 @@ void RenderThemeMac::adjustSliderThumbSize(RenderObject* o) const } #if ENABLE(VIDEO) - else if (o->style()->appearance() == MediaSliderThumbPart) { + adjustMediaSliderThumbSize(o); +#endif +} + +#if ENABLE(VIDEO) + +void RenderThemeMac::adjustMediaSliderThumbSize(RenderObject* o) const +{ + if (o->style()->appearance() == MediaSliderThumbPart) { int width = mediaSliderThumbWidth; int height = mediaSliderThumbHeight; @@ -1539,15 +1573,12 @@ void RenderThemeMac::adjustSliderThumbSize(RenderObject* o) const height = size.height; } + float zoomLevel = o->style()->effectiveZoom(); o->style()->setWidth(Length(static_cast<int>(width * zoomLevel), Fixed)); o->style()->setHeight(Length(static_cast<int>(height * zoomLevel), Fixed)); } -#endif } - -#if ENABLE(VIDEO) - enum WKMediaControllerThemeState { MediaUIPartDisabledFlag = 1 << 0, MediaUIPartPressedFlag = 1 << 1, @@ -1759,10 +1790,15 @@ bool RenderThemeMac::paintMediaTimeRemaining(RenderObject* o, const RenderObject String RenderThemeMac::extraMediaControlsStyleSheet() { +#if PLATFORM(MAC) if (mediaControllerTheme() == MediaControllerThemeQuickTime) return String(mediaControlsQuickTimeUserAgentStyleSheet, sizeof(mediaControlsQuickTimeUserAgentStyleSheet)); else return String(); +#else + ASSERT_NOT_REACHED(); + return String(); +#endif } bool RenderThemeMac::shouldRenderMediaControlPart(ControlPart part, Element* element) diff --git a/WebCore/rendering/RenderTreeAsText.cpp b/WebCore/rendering/RenderTreeAsText.cpp index 75c35ba..311854e 100644 --- a/WebCore/rendering/RenderTreeAsText.cpp +++ b/WebCore/rendering/RenderTreeAsText.cpp @@ -34,6 +34,7 @@ #include "HTMLElement.h" #include "HTMLNames.h" #include "InlineTextBox.h" +#include "PrintContext.h" #include "RenderBR.h" #include "RenderFileUploadControl.h" #include "RenderInline.h" @@ -51,6 +52,7 @@ #if ENABLE(SVG) #include "RenderPath.h" #include "RenderSVGContainer.h" +#include "RenderSVGGradientStop.h" #include "RenderSVGImage.h" #include "RenderSVGInlineText.h" #include "RenderSVGRoot.h" @@ -396,8 +398,12 @@ void write(TextStream& ts, const RenderObject& o, int indent, RenderAsTextBehavi write(ts, *toRenderPath(&o), indent); return; } - if (o.isSVGResource()) { - writeSVGResource(ts, o, indent); + if (o.isSVGGradientStop()) { + writeSVGGradientStop(ts, *toRenderSVGGradientStop(&o), indent); + return; + } + if (o.isSVGResourceContainer()) { + writeSVGResourceContainer(ts, o, indent); return; } if (o.isSVGContainer()) { @@ -612,6 +618,13 @@ static void writeSelection(TextStream& ts, const RenderObject* o) String externalRepresentation(Frame* frame, RenderAsTextBehavior behavior) { + PrintContext printContext(frame); + if (behavior & RenderAsTextPrintingMode) { + if (!frame->contentRenderer()) + return String(); + printContext.begin(frame->contentRenderer()->width()); + } + frame->document()->updateLayout(); RenderObject* o = frame->contentRenderer(); @@ -619,9 +632,6 @@ String externalRepresentation(Frame* frame, RenderAsTextBehavior behavior) return String(); TextStream ts; -#if ENABLE(SVG) - writeRenderResources(ts, o->document()); -#endif if (o->hasLayer()) { RenderLayer* l = toRenderBox(o)->layer(); writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height()), 0, behavior); diff --git a/WebCore/rendering/RenderTreeAsText.h b/WebCore/rendering/RenderTreeAsText.h index 4da0bab..1427342 100644 --- a/WebCore/rendering/RenderTreeAsText.h +++ b/WebCore/rendering/RenderTreeAsText.h @@ -39,10 +39,12 @@ enum RenderAsTextBehaviorFlags { RenderAsTextShowAllLayers = 1 << 0, // Dump all layers, not just those that would paint. RenderAsTextShowLayerNesting = 1 << 1, // Annotate the layer lists. RenderAsTextShowCompositedLayers = 1 << 2, // Show which layers are composited. - RenderAsTextShowAddresses = 1 << 3 // Show layer and renderer addresses. + RenderAsTextShowAddresses = 1 << 3, // Show layer and renderer addresses. + RenderAsTextPrintingMode = 1 << 4 // Dump the tree in printing mode. }; typedef unsigned RenderAsTextBehavior; +// You don't need pageWidthInPixels if you don't specify RenderAsTextInPrintingMode. String externalRepresentation(Frame*, RenderAsTextBehavior = RenderAsTextBehaviorNormal); void write(TextStream&, const RenderObject&, int indent = 0, RenderAsTextBehavior = RenderAsTextBehaviorNormal); diff --git a/WebCore/rendering/RenderVideo.cpp b/WebCore/rendering/RenderVideo.cpp index ad25c22..610fb5f 100644 --- a/WebCore/rendering/RenderVideo.cpp +++ b/WebCore/rendering/RenderVideo.cpp @@ -50,7 +50,7 @@ using namespace HTMLNames; RenderVideo::RenderVideo(HTMLVideoElement* video) : RenderMedia(video) { - if (video->player()) + if (video->player() && video->readyState() >= HTMLVideoElement::HAVE_METADATA) setIntrinsicSize(video->player()->naturalSize()); else { // When the natural size of the video is unavailable, we use the provided @@ -101,7 +101,11 @@ void RenderVideo::videoSizeChanged() if (!player()) return; IntSize size = player()->naturalSize(); - if (!size.isEmpty() && size != intrinsicSize()) { + if (size.isEmpty()) { + if (node()->ownerDocument() && node()->ownerDocument()->isMediaDocument()) + return; + } + if (size != intrinsicSize()) { setIntrinsicSize(size); setPrefWidthsDirty(true); setNeedsLayout(true); diff --git a/WebCore/rendering/RenderView.cpp b/WebCore/rendering/RenderView.cpp index a95ffdd..449e293 100644 --- a/WebCore/rendering/RenderView.cpp +++ b/WebCore/rendering/RenderView.cpp @@ -747,16 +747,6 @@ bool RenderView::usesCompositing() const return m_compositor && m_compositor->inCompositingMode(); } -void RenderView::compositingStateChanged(bool) -{ - Element* elt = document()->ownerElement(); - if (!elt) - return; - - // Trigger a recalcStyle in the parent document, to update compositing in that document. - elt->setNeedsStyleRecalc(SyntheticStyleChange); -} - RenderLayerCompositor* RenderView::compositor() { if (!m_compositor) diff --git a/WebCore/rendering/RenderView.h b/WebCore/rendering/RenderView.h index 0751866..05c3876 100644 --- a/WebCore/rendering/RenderView.h +++ b/WebCore/rendering/RenderView.h @@ -166,7 +166,6 @@ public: #if USE(ACCELERATED_COMPOSITING) RenderLayerCompositor* compositor(); bool usesCompositing() const; - void compositingStateChanged(bool nowComposited); #endif protected: diff --git a/WebCore/rendering/RenderWidget.cpp b/WebCore/rendering/RenderWidget.cpp index 485baa3..15c75f1 100644 --- a/WebCore/rendering/RenderWidget.cpp +++ b/WebCore/rendering/RenderWidget.cpp @@ -320,8 +320,8 @@ void RenderWidget::updateWidgetPosition() FloatPoint absPos = localToAbsolute(); absPos.move(borderLeft() + paddingLeft(), borderTop() + paddingTop()); - int w = width() - borderLeft() - borderRight() - paddingLeft() - paddingRight(); - int h = height() - borderTop() - borderBottom() - paddingTop() - paddingBottom(); + int w = width() - borderAndPaddingWidth(); + int h = height() - borderAndPaddingHeight(); bool boundsChanged = setWidgetGeometry(IntRect(absPos.x(), absPos.y(), w, h)); diff --git a/WebCore/rendering/SVGCharacterData.cpp b/WebCore/rendering/SVGCharacterData.cpp new file mode 100644 index 0000000..394a303 --- /dev/null +++ b/WebCore/rendering/SVGCharacterData.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "SVGCharacterData.h" + +#if ENABLE(SVG) +#include "AffineTransform.h" + +namespace WebCore { + +bool SVGChar::isHidden() const +{ + return pathData && pathData->hidden; +} + +AffineTransform SVGChar::characterTransform() const +{ + AffineTransform ctm; + + // Rotate character around angle, and possibly scale. + ctm.translate(x, y); + ctm.rotate(angle); + + if (pathData) { + ctm.scaleNonUniform(pathData->xScale, pathData->yScale); + ctm.translate(pathData->xShift, pathData->yShift); + ctm.rotate(pathData->orientationAngle); + } + + ctm.translate(orientationShiftX - x, orientationShiftY - y); + return ctm; +} + +} // namespace WebCore + +#endif // ENABLE(SVG) diff --git a/WebCore/rendering/SVGCharacterData.h b/WebCore/rendering/SVGCharacterData.h new file mode 100644 index 0000000..68682c9 --- /dev/null +++ b/WebCore/rendering/SVGCharacterData.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. 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 SVGCharacterData_h +#define SVGCharacterData_h + +#if ENABLE(SVG) +#include <wtf/HashMap.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class AffineTransform; +class RenderObject; + +// Holds extra data, when the character is laid out on a path +struct SVGCharOnPath : RefCounted<SVGCharOnPath> { + static PassRefPtr<SVGCharOnPath> create() { return adoptRef(new SVGCharOnPath); } + + float xScale; + float yScale; + + float xShift; + float yShift; + + float orientationAngle; + + bool hidden : 1; + +private: + SVGCharOnPath() + : xScale(1.0f) + , yScale(1.0f) + , xShift(0.0f) + , yShift(0.0f) + , orientationAngle(0.0f) + , hidden(false) + { + } +}; + +struct SVGChar { + SVGChar() + : x(0.0f) + , y(0.0f) + , angle(0.0f) + , orientationShiftX(0.0f) + , orientationShiftY(0.0f) + , drawnSeperated(false) + , newTextChunk(false) + { + } + + float x; + float y; + float angle; + + float orientationShiftX; + float orientationShiftY; + + RefPtr<SVGCharOnPath> pathData; + + // Determines wheter this char needs to be drawn seperated + bool drawnSeperated : 1; + + // Determines wheter this char starts a new chunk + bool newTextChunk : 1; + + // Helper methods + bool isHidden() const; + AffineTransform characterTransform() const; +}; + +struct SVGTextDecorationInfo { + // ETextDecoration is meant to be used here + HashMap<int, RenderObject*> fillServerMap; + HashMap<int, RenderObject*> strokeServerMap; +}; + +} // namespace WebCore + +#endif // ENABLE(SVG) +#endif // SVGCharacterData_h diff --git a/WebCore/rendering/SVGCharacterLayoutInfo.cpp b/WebCore/rendering/SVGCharacterLayoutInfo.cpp index 7e85672..04f0067 100644 --- a/WebCore/rendering/SVGCharacterLayoutInfo.cpp +++ b/WebCore/rendering/SVGCharacterLayoutInfo.cpp @@ -1,6 +1,4 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * * This library is free software; you can redistribute it and/or @@ -21,16 +19,16 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGCharacterLayoutInfo.h" +#if ENABLE(SVG) #include "InlineFlowBox.h" #include "InlineTextBox.h" +#include "RenderSVGTextPath.h" +#include "SVGCharacterData.h" #include "SVGLengthList.h" #include "SVGNumberList.h" #include "SVGTextPositioningElement.h" -#include "RenderSVGTextPath.h" #include <float.h> @@ -161,6 +159,19 @@ float SVGCharacterLayoutInfo::baselineShiftValueNext() const return baselineShiftStack.last(); } + +bool SVGCharacterLayoutInfo::isInitialLayout() const +{ + return xStack.isEmpty() + && yStack.isEmpty() + && dxStack.isEmpty() + && dyStack.isEmpty() + && angleStack.isEmpty() + && baselineShiftStack.isEmpty() + && curx == 0.0f + && cury == 0.0f; +} + void SVGCharacterLayoutInfo::processedSingleCharacter() { xStackWalk(); @@ -249,7 +260,6 @@ bool SVGCharacterLayoutInfo::nextPathLayoutPointAndAngle(float glyphAdvance, flo angle = layoutPath.normalAngleAtLength(offset, ok); ASSERT(ok); - // fprintf(stderr, "t: %f, x: %f, y: %f, angle: %f, glyphAdvance: %f\n", currentOffset, x, y, angle, glyphAdvance); return true; } @@ -269,10 +279,7 @@ void SVGCharacterLayoutInfo::setInPathLayout(bool value) void SVGCharacterLayoutInfo::addLayoutInformation(InlineFlowBox* flowBox, float textAnchorStartOffset) { - bool isInitialLayout = xStack.isEmpty() && yStack.isEmpty() && - dxStack.isEmpty() && dyStack.isEmpty() && - angleStack.isEmpty() && baselineShiftStack.isEmpty() && - curx == 0.0f && cury == 0.0f; + bool wasInitialLayout = isInitialLayout(); RenderSVGTextPath* textPath = toRenderSVGTextPath(flowBox->renderer()); Path path = textPath->layoutPath(); @@ -296,7 +303,7 @@ void SVGCharacterLayoutInfo::addLayoutInformation(InlineFlowBox* flowBox, float // Only baseline-shift is handled through the normal layout system addStackContent(BaselineShiftStack, baselineShift); - if (isInitialLayout) { + if (wasInitialLayout) { xStackChanged = false; yStackChanged = false; dxStackChanged = false; @@ -308,11 +315,7 @@ void SVGCharacterLayoutInfo::addLayoutInformation(InlineFlowBox* flowBox, float void SVGCharacterLayoutInfo::addLayoutInformation(SVGTextPositioningElement* element) { - bool isInitialLayout = xStack.isEmpty() && yStack.isEmpty() && - dxStack.isEmpty() && dyStack.isEmpty() && - angleStack.isEmpty() && baselineShiftStack.isEmpty() && - curx == 0.0f && cury == 0.0f; - + bool wasInitialLayout = isInitialLayout(); float baselineShift = calculateBaselineShift(element->renderer()); addStackContent(XStack, element->x(), element); @@ -322,7 +325,7 @@ void SVGCharacterLayoutInfo::addLayoutInformation(SVGTextPositioningElement* ele addStackContent(AngleStack, element->rotate()); addStackContent(BaselineShiftStack, baselineShift); - if (isInitialLayout) { + if (wasInitialLayout) { xStackChanged = false; yStackChanged = false; dxStackChanged = false; @@ -344,7 +347,7 @@ void SVGCharacterLayoutInfo::addStackContent(StackType type, SVGNumberList* list ExceptionCode ec = 0; for (unsigned i = 0; i < length; ++i) { float value = list->getItem(i, ec); - ASSERT(ec == 0); + ASSERT(!ec); newLayoutInfo.append(value); } @@ -363,7 +366,7 @@ void SVGCharacterLayoutInfo::addStackContent(StackType type, SVGLengthList* list ExceptionCode ec = 0; for (unsigned i = 0; i < length; ++i) { float value = list->getItem(i, ec).value(context); - ASSERT(ec == 0); + ASSERT(!ec); newLayoutInfo.append(value); } @@ -507,29 +510,6 @@ void SVGCharacterLayoutInfo::baselineShiftStackWalk() } } -bool SVGChar::isHidden() const -{ - return pathData && pathData->hidden; -} - -AffineTransform SVGChar::characterTransform() const -{ - AffineTransform ctm; - - // Rotate character around angle, and possibly scale. - ctm.translate(x, y); - ctm.rotate(angle); - - if (pathData) { - ctm.scaleNonUniform(pathData->xScale, pathData->yScale); - ctm.translate(pathData->xShift, pathData->yShift); - ctm.rotate(pathData->orientationAngle); - } - - ctm.translate(orientationShiftX - x, orientationShiftY - y); - return ctm; -} - } // namespace WebCore #endif // ENABLE(SVG) diff --git a/WebCore/rendering/SVGCharacterLayoutInfo.h b/WebCore/rendering/SVGCharacterLayoutInfo.h index f0d1fa4..16fd740 100644 --- a/WebCore/rendering/SVGCharacterLayoutInfo.h +++ b/WebCore/rendering/SVGCharacterLayoutInfo.h @@ -1,6 +1,4 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * * This library is free software; you can redistribute it and/or @@ -24,21 +22,14 @@ #define SVGCharacterLayoutInfo_h #if ENABLE(SVG) -#include "AffineTransform.h" -#include "SVGRenderStyle.h" -#include "SVGTextContentElement.h" - +#include "Path.h" #include <wtf/Assertions.h> -#include <wtf/HashMap.h> -#include <wtf/HashSet.h> -#include <wtf/RefCounted.h> #include <wtf/Vector.h> namespace WebCore { -class InlineBox; class InlineFlowBox; -class SVGInlineTextBox; +class SVGElement; class SVGLengthList; class SVGNumberList; class SVGTextPositioningElement; @@ -151,6 +142,8 @@ private: void angleStackWalk(); void baselineShiftStackWalk(); + bool isInitialLayout() const; + private: bool xStackChanged : 1; bool yStackChanged : 1; @@ -174,211 +167,6 @@ private: Vector<float> baselineShiftStack; }; -// Holds extra data, when the character is laid out on a path -struct SVGCharOnPath : RefCounted<SVGCharOnPath> { - static PassRefPtr<SVGCharOnPath> create() { return adoptRef(new SVGCharOnPath); } - - float xScale; - float yScale; - - float xShift; - float yShift; - - float orientationAngle; - - bool hidden : 1; - -private: - SVGCharOnPath() - : xScale(1.0f) - , yScale(1.0f) - , xShift(0.0f) - , yShift(0.0f) - , orientationAngle(0.0f) - , hidden(false) - { - } -}; - -struct SVGChar { - SVGChar() - : x(0.0f) - , y(0.0f) - , angle(0.0f) - , orientationShiftX(0.0f) - , orientationShiftY(0.0f) - , pathData() - , drawnSeperated(false) - , newTextChunk(false) - { - } - - ~SVGChar() - { - } - - float x; - float y; - float angle; - - float orientationShiftX; - float orientationShiftY; - - RefPtr<SVGCharOnPath> pathData; - - // Determines wheter this char needs to be drawn seperated - bool drawnSeperated : 1; - - // Determines wheter this char starts a new chunk - bool newTextChunk : 1; - - // Helper methods - bool isHidden() const; - AffineTransform characterTransform() const; -}; - -struct SVGInlineBoxCharacterRange { - SVGInlineBoxCharacterRange() - : startOffset(INT_MIN) - , endOffset(INT_MIN) - , box(0) - { - } - - bool isOpen() const { return (startOffset == endOffset) && (endOffset == INT_MIN); } - bool isClosed() const { return startOffset != INT_MIN && endOffset != INT_MIN; } - - int startOffset; - int endOffset; - - InlineBox* box; -}; - -// Convenience typedef -typedef SVGTextContentElement::SVGLengthAdjustType ELengthAdjust; - -struct SVGTextChunk { - SVGTextChunk() - : anchor(TA_START) - , textLength(0.0f) - , lengthAdjust(SVGTextContentElement::LENGTHADJUST_SPACING) - , ctm() - , isVerticalText(false) - , isTextPath(false) - , start(0) - , end(0) - { } - - // text-anchor support - ETextAnchor anchor; - - // textLength & lengthAdjust support - float textLength; - ELengthAdjust lengthAdjust; - AffineTransform ctm; - - // status flags - bool isVerticalText : 1; - bool isTextPath : 1; - - // main chunk data - Vector<SVGChar>::iterator start; - Vector<SVGChar>::iterator end; - - Vector<SVGInlineBoxCharacterRange> boxes; -}; - -struct SVGTextChunkWalkerBase { - virtual ~SVGTextChunkWalkerBase() { } - - virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, - const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) = 0; - - // Followings methods are only used for painting text chunks - virtual void start(InlineBox*) = 0; - virtual void end(InlineBox*) = 0; -}; - -template<typename CallbackClass> -struct SVGTextChunkWalker : public SVGTextChunkWalkerBase { -public: - typedef void (CallbackClass::*SVGTextChunkWalkerCallback)(SVGInlineTextBox* textBox, - int startOffset, - const AffineTransform& chunkCtm, - const Vector<SVGChar>::iterator& start, - const Vector<SVGChar>::iterator& end); - - // These callbacks are only used for painting! - typedef void (CallbackClass::*SVGTextChunkStartCallback)(InlineBox* box); - typedef void (CallbackClass::*SVGTextChunkEndCallback)(InlineBox* box); - - SVGTextChunkWalker(CallbackClass* object, - SVGTextChunkWalkerCallback walker, - SVGTextChunkStartCallback start = 0, - SVGTextChunkEndCallback end = 0) - : m_object(object) - , m_walkerCallback(walker) - , m_startCallback(start) - , m_endCallback(end) - { - ASSERT(object); - ASSERT(walker); - } - - virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, - const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) - { - (*m_object.*m_walkerCallback)(textBox, startOffset, chunkCtm, start, end); - } - - // Followings methods are only used for painting text chunks - virtual void start(InlineBox* box) - { - if (m_startCallback) - (*m_object.*m_startCallback)(box); - else - ASSERT_NOT_REACHED(); - } - - virtual void end(InlineBox* box) - { - if (m_endCallback) - (*m_object.*m_endCallback)(box); - else - ASSERT_NOT_REACHED(); - } - -private: - CallbackClass* m_object; - SVGTextChunkWalkerCallback m_walkerCallback; - SVGTextChunkStartCallback m_startCallback; - SVGTextChunkEndCallback m_endCallback; -}; - -struct SVGTextChunkLayoutInfo { - SVGTextChunkLayoutInfo(Vector<SVGTextChunk>& textChunks) - : assignChunkProperties(true) - , handlingTextPath(false) - , svgTextChunks(textChunks) - , it(0) - { - } - - bool assignChunkProperties : 1; - bool handlingTextPath : 1; - - Vector<SVGTextChunk>& svgTextChunks; - Vector<SVGChar>::iterator it; - - SVGTextChunk chunk; -}; - -struct SVGTextDecorationInfo { - // ETextDecoration is meant to be used here - HashMap<int, RenderObject*> fillServerMap; - HashMap<int, RenderObject*> strokeServerMap; -}; - } // namespace WebCore #endif // ENABLE(SVG) diff --git a/WebCore/rendering/SVGInlineTextBox.cpp b/WebCore/rendering/SVGInlineTextBox.cpp index bda512f..8b35507 100644 --- a/WebCore/rendering/SVGInlineTextBox.cpp +++ b/WebCore/rendering/SVGInlineTextBox.cpp @@ -30,7 +30,7 @@ #include "GraphicsContext.h" #include "InlineFlowBox.h" #include "Range.h" -#include "SVGPaintServer.h" +#include "RenderSVGResource.h" #include "SVGRootInlineBox.h" #include "Text.h" @@ -418,10 +418,9 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t TextRun run = svgTextRunForInlineTextBox(chars, length, styleToUse, this, svgChar.x); #if ENABLE(SVG_FONTS) - // SVG Fonts need access to the paint server used to draw the current text chunk. - // They need to be able to call renderPath() on a SVGPaintServer object. - ASSERT(textPaintInfo.activePaintServer); - run.setActivePaintServer(textPaintInfo.activePaintServer); + // SVG Fonts need access to the painting resource used to draw the current text chunk. + ASSERT(textPaintInfo.activePaintingResource); + run.setActivePaintingResource(textPaintInfo.activePaintingResource); #endif int selectionStart = 0; @@ -569,18 +568,20 @@ void SVGInlineTextBox::paintDecoration(ETextDecoration decoration, GraphicsConte if (isFilled) { if (RenderObject* fillObject = info.fillServerMap.get(decoration)) { - if (SVGPaintServer* fillPaintServer = SVGPaintServer::fillPaintServer(fillObject->style(), fillObject)) { + if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(fillObject, fillObject->style())) { context->addPath(pathForDecoration(decoration, fillObject, tx, ty, width)); - fillPaintServer->draw(context, fillObject, ApplyToFillTargetType); + if (fillPaintingResource->applyResource(fillObject, fillObject->style(), context, ApplyToFillMode)) + fillPaintingResource->postApplyResource(fillObject, context, ApplyToFillMode); } } } if (isStroked) { if (RenderObject* strokeObject = info.strokeServerMap.get(decoration)) { - if (SVGPaintServer* strokePaintServer = SVGPaintServer::strokePaintServer(strokeObject->style(), strokeObject)) { + if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(strokeObject, strokeObject->style())) { context->addPath(pathForDecoration(decoration, strokeObject, tx, ty, width)); - strokePaintServer->draw(context, strokeObject, ApplyToStrokeTargetType); + if (strokePaintingResource->applyResource(strokeObject, strokeObject->style(), context, ApplyToStrokeMode)) + strokePaintingResource->postApplyResource(strokeObject, context, ApplyToStrokeMode); } } } diff --git a/WebCore/rendering/SVGInlineTextBox.h b/WebCore/rendering/SVGInlineTextBox.h index 596fdf3..c586ddd 100644 --- a/WebCore/rendering/SVGInlineTextBox.h +++ b/WebCore/rendering/SVGInlineTextBox.h @@ -24,6 +24,7 @@ #if ENABLE(SVG) #include "InlineTextBox.h" +#include "RenderSVGResource.h" namespace WebCore { @@ -42,9 +43,13 @@ namespace WebCore { }; struct SVGTextPaintInfo { - SVGTextPaintInfo() : activePaintServer(0), subphase(SVGTextPaintSubphaseBackground) {} + SVGTextPaintInfo() + : activePaintingResource(0) + , subphase(SVGTextPaintSubphaseBackground) + { + } - SVGPaintServer* activePaintServer; + RenderSVGResource* activePaintingResource; SVGTextPaintSubphase subphase; }; diff --git a/WebCore/rendering/SVGRenderSupport.cpp b/WebCore/rendering/SVGRenderSupport.cpp index dd67746..2600512 100644 --- a/WebCore/rendering/SVGRenderSupport.cpp +++ b/WebCore/rendering/SVGRenderSupport.cpp @@ -31,6 +31,7 @@ #include "AffineTransform.h" #include "Document.h" #include "ImageBuffer.h" +#include "NodeRenderStyle.h" #include "RenderObject.h" #include "RenderSVGContainer.h" #include "RenderSVGResource.h" @@ -92,7 +93,7 @@ bool SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject ASSERT(svgElement && svgElement->document() && svgElement->isStyled()); SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement); - const RenderStyle* style = object->style(); + RenderStyle* style = object->style(); ASSERT(style); const SVGRenderStyle* svgStyle = style->svgStyle(); @@ -132,19 +133,19 @@ bool SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject #endif if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(document, maskerId)) { - if (!masker->applyResource(object, paintInfo.context)) + if (!masker->applyResource(object, style, paintInfo.context, ApplyToDefaultMode)) return false; } else if (!maskerId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement); if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(document, clipperId)) - clipper->applyResource(object, paintInfo.context); + clipper->applyResource(object, style, paintInfo.context, ApplyToDefaultMode); else if (!clipperId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement); #if ENABLE(FILTERS) if (filter) { - if (!filter->applyResource(object, paintInfo.context)) + if (!filter->applyResource(object, style, paintInfo.context, ApplyToDefaultMode)) return false; } else if (!filterId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement); @@ -167,7 +168,7 @@ void SVGRenderBase::finishRenderSVGContent(RenderObject* object, RenderObject::P #if ENABLE(FILTERS) if (filter) { - filter->postApplyResource(object, paintInfo.context); + filter->postApplyResource(object, paintInfo.context, ApplyToDefaultMode); paintInfo.context = savedContext; } #endif @@ -306,23 +307,57 @@ FloatRect SVGRenderBase::maskerBoundingBoxForRenderer(const RenderObject* object return FloatRect(); } +static inline void invalidatePaintingResource(SVGPaint* paint, RenderObject* object) +{ + ASSERT(paint); + + SVGPaint::SVGPaintType paintType = paint->paintType(); + if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) + return; + + AtomicString id(SVGURIReference::getTarget(paint->uri())); + if (RenderSVGResourceContainer* paintingResource = getRenderSVGResourceContainerById(object->document(), id)) + paintingResource->invalidateClient(object); +} + void deregisterFromResources(RenderObject* object) { - // We only have the renderer for masker and clipper at the moment. - if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(object->document(), object->style()->svgStyle()->maskerResource())) + ASSERT(object); + ASSERT(object->style()); + + Document* document = object->document(); + ASSERT(document); + + const SVGRenderStyle* svgStyle = object->style()->svgStyle(); + ASSERT(svgStyle); + + // Masker + if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(document, svgStyle->maskerResource())) masker->invalidateClient(object); - if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(object->document(), object->style()->svgStyle()->clipperResource())) + + // Clipper + if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(document, svgStyle->clipperResource())) clipper->invalidateClient(object); + + // Filter #if ENABLE(FILTERS) - if (RenderSVGResourceFilter* filter = getRenderSVGResourceById<RenderSVGResourceFilter>(object->document(), object->style()->svgStyle()->filterResource())) + if (RenderSVGResourceFilter* filter = getRenderSVGResourceById<RenderSVGResourceFilter>(document, svgStyle->filterResource())) filter->invalidateClient(object); #endif - if (RenderSVGResourceMarker* startMarker = getRenderSVGResourceById<RenderSVGResourceMarker>(object->document(), object->style()->svgStyle()->markerStartResource())) + + // Markers + if (RenderSVGResourceMarker* startMarker = getRenderSVGResourceById<RenderSVGResourceMarker>(document, svgStyle->markerStartResource())) startMarker->invalidateClient(object); - if (RenderSVGResourceMarker* midMarker = getRenderSVGResourceById<RenderSVGResourceMarker>(object->document(), object->style()->svgStyle()->markerMidResource())) + if (RenderSVGResourceMarker* midMarker = getRenderSVGResourceById<RenderSVGResourceMarker>(document, svgStyle->markerMidResource())) midMarker->invalidateClient(object); - if (RenderSVGResourceMarker* endMarker = getRenderSVGResourceById<RenderSVGResourceMarker>(object->document(), object->style()->svgStyle()->markerEndResource())) + if (RenderSVGResourceMarker* endMarker = getRenderSVGResourceById<RenderSVGResourceMarker>(document, svgStyle->markerEndResource())) endMarker->invalidateClient(object); + + // Gradients/Patterns + if (svgStyle->hasFill()) + invalidatePaintingResource(svgStyle->fillPaint(), object); + if (svgStyle->hasStroke()) + invalidatePaintingResource(svgStyle->strokePaint(), object); } void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const AffineTransform& localToAncestorTransform) @@ -334,6 +369,42 @@ void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const AffineT paintInfo.rect = localToAncestorTransform.inverse().mapRect(paintInfo.rect); } +DashArray dashArrayFromRenderingStyle(const RenderStyle* style, RenderStyle* rootStyle) +{ + DashArray array; + + CSSValueList* dashes = style->svgStyle()->strokeDashArray(); + if (dashes) { + CSSPrimitiveValue* dash = 0; + unsigned long len = dashes->length(); + for (unsigned long i = 0; i < len; i++) { + dash = static_cast<CSSPrimitiveValue*>(dashes->itemWithoutBoundsCheck(i)); + if (!dash) + continue; + + array.append((float) dash->computeLengthFloat(const_cast<RenderStyle*>(style), rootStyle)); + } + } + + return array; +} + +void applyStrokeStyleToContext(GraphicsContext* context, const RenderStyle* style, const RenderObject* object) +{ + context->setStrokeThickness(SVGRenderStyle::cssPrimitiveToLength(object, style->svgStyle()->strokeWidth(), 1.0f)); + context->setLineCap(style->svgStyle()->capStyle()); + context->setLineJoin(style->svgStyle()->joinStyle()); + if (style->svgStyle()->joinStyle() == MiterJoin) + context->setMiterLimit(style->svgStyle()->strokeMiterLimit()); + + const DashArray& dashes = dashArrayFromRenderingStyle(object->style(), object->document()->documentElement()->renderStyle()); + float dashOffset = SVGRenderStyle::cssPrimitiveToLength(object, style->svgStyle()->strokeDashOffset(), 0.0f); + if (dashes.isEmpty()) + context->setStrokeStyle(SolidStroke); + else + context->setLineDash(dashes, dashOffset); +} + const RenderObject* findTextRootObject(const RenderObject* start) { while (start && !start->isSVGText()) diff --git a/WebCore/rendering/SVGRenderSupport.h b/WebCore/rendering/SVGRenderSupport.h index 4b59b71..b8a014a 100644 --- a/WebCore/rendering/SVGRenderSupport.h +++ b/WebCore/rendering/SVGRenderSupport.h @@ -25,6 +25,7 @@ #define SVGRenderBase_h #if ENABLE(SVG) +#include "DashArray.h" #include "RenderObject.h" #include "SVGElement.h" #include "SVGStyledElement.h" @@ -42,8 +43,6 @@ class SVGRenderBase { public: virtual ~SVGRenderBase(); - virtual const SVGRenderBase* toSVGRenderBase() const { return this; } - // FIXME: These are only public for SVGRootInlineBox. // It's unclear if these should be exposed or not. SVGRootInlineBox may // pass the wrong RenderObject* and boundingBox to these functions. @@ -56,8 +55,8 @@ public: // Helper function determining wheter overflow is hidden static bool isOverflowHidden(const RenderObject*); + // strokeBoundingBox() includes the marker boundaries for a RenderPath object virtual FloatRect strokeBoundingBox() const { return FloatRect(); } - virtual FloatRect markerBoundingBox() const { return FloatRect(); } // returns the bounding box of filter, clipper, marker and masker (or the empty rect if no filter) in local coordinates FloatRect filterBoundingBoxForRenderer(const RenderObject*) const; @@ -85,7 +84,11 @@ void renderSubtreeToImage(ImageBuffer*, RenderObject*); void deregisterFromResources(RenderObject*); void clampImageBufferSizeToViewport(FrameView*, IntSize& imageBufferSize); +void applyStrokeStyleToContext(GraphicsContext*, const RenderStyle*, const RenderObject*); +DashArray dashArrayFromRenderingStyle(const RenderStyle* style, RenderStyle* rootStyle); + const RenderObject* findTextRootObject(const RenderObject* start); + } // namespace WebCore #endif // ENABLE(SVG) diff --git a/WebCore/rendering/SVGRenderTreeAsText.cpp b/WebCore/rendering/SVGRenderTreeAsText.cpp index 0f1f15d..f6fbae2 100644 --- a/WebCore/rendering/SVGRenderTreeAsText.cpp +++ b/WebCore/rendering/SVGRenderTreeAsText.cpp @@ -34,26 +34,37 @@ #include "GraphicsTypes.h" #include "HTMLNames.h" #include "InlineTextBox.h" +#include "LinearGradientAttributes.h" #include "NodeRenderStyle.h" #include "Path.h" +#include "PatternAttributes.h" +#include "RadialGradientAttributes.h" #include "RenderImage.h" #include "RenderPath.h" #include "RenderSVGContainer.h" +#include "RenderSVGGradientStop.h" #include "RenderSVGInlineText.h" #include "RenderSVGResourceClipper.h" #include "RenderSVGResourceFilter.h" +#include "RenderSVGResourceGradient.h" +#include "RenderSVGResourceLinearGradient.h" #include "RenderSVGResourceMarker.h" #include "RenderSVGResourceMasker.h" +#include "RenderSVGResourcePattern.h" +#include "RenderSVGResourceRadialGradient.h" +#include "RenderSVGResourceSolidColor.h" #include "RenderSVGRoot.h" #include "RenderSVGText.h" #include "RenderTreeAsText.h" #include "SVGCharacterLayoutInfo.h" #include "SVGInlineTextBox.h" -#include "SVGPaintServerGradient.h" -#include "SVGPaintServerPattern.h" -#include "SVGPaintServerSolid.h" +#include "SVGLinearGradientElement.h" +#include "SVGPatternElement.h" +#include "SVGRadialGradientElement.h" #include "SVGRootInlineBox.h" +#include "SVGStopElement.h" #include "SVGStyledElement.h" + #include <math.h> namespace WebCore { @@ -307,6 +318,47 @@ static TextStream& operator<<(TextStream& ts, LineJoin style) return ts; } +// FIXME: Maybe this should be in Gradient.cpp +static TextStream& operator<<(TextStream& ts, GradientSpreadMethod mode) +{ + switch (mode) { + case SpreadMethodPad: + ts << "PAD"; + break; + case SpreadMethodRepeat: + ts << "REPEAT"; + break; + case SpreadMethodReflect: + ts << "REFLECT"; + break; + } + + return ts; +} + +static void writeSVGPaintingResource(TextStream& ts, RenderSVGResource* resource) +{ + if (resource->resourceType() == SolidColorResourceType) { + ts << "[type=SOLID] [color=" << static_cast<RenderSVGResourceSolidColor*>(resource)->color() << "]"; + return; + } + + // All other resources derive from RenderSVGResourceContainer + RenderSVGResourceContainer* container = static_cast<RenderSVGResourceContainer*>(resource); + Node* node = container->node(); + ASSERT(node); + ASSERT(node->isSVGElement()); + + if (resource->resourceType() == PatternResourceType) + ts << "[type=PATTERN]"; + else if (resource->resourceType() == LinearGradientResourceType) + ts << "[type=LINEAR-GRADIENT]"; + else if (resource->resourceType() == RadialGradientResourceType) + ts << "[type=RADIAL-GRADIENT]"; + + ts << " [id=\"" << static_cast<SVGElement*>(node)->getIDAttribute() << "\"]"; +} + static void writeStyle(TextStream& ts, const RenderObject& object) { const RenderStyle* style = object.style(); @@ -318,12 +370,11 @@ static void writeStyle(TextStream& ts, const RenderObject& object) writeIfNotDefault(ts, "opacity", style->opacity(), RenderStyle::initialOpacity()); if (object.isRenderPath()) { const RenderPath& path = static_cast<const RenderPath&>(object); - SVGPaintServer* strokePaintServer = SVGPaintServer::strokePaintServer(style, &path); - if (strokePaintServer) { + + if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(&path, path.style())) { TextStreamSeparator s(" "); - ts << " [stroke={"; - if (strokePaintServer) - ts << s << *strokePaintServer; + ts << " [stroke={" << s; + writeSVGPaintingResource(ts, strokePaintingResource); double dashOffset = SVGRenderStyle::cssPrimitiveToLength(&path, svgStyle->strokeDashOffset(), 0.0f); const DashArray& dashArray = dashArrayFromRenderingStyle(style, object.document()->documentElement()->renderStyle()); @@ -340,12 +391,11 @@ static void writeStyle(TextStream& ts, const RenderObject& object) ts << "}]"; } - SVGPaintServer* fillPaintServer = SVGPaintServer::fillPaintServer(style, &path); - if (fillPaintServer) { + + if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(&path, path.style())) { TextStreamSeparator s(" "); - ts << " [fill={"; - if (fillPaintServer) - ts << s << *fillPaintServer; + ts << " [fill={" << s; + writeSVGPaintingResource(ts, fillPaintingResource); writeIfNotDefault(ts, "opacity", svgStyle->fillOpacity(), 1.0f); writeIfNotDefault(ts, "fill rule", svgStyle->fillRule(), RULE_NONZERO); @@ -515,7 +565,23 @@ static void writeChildren(TextStream& ts, const RenderObject& object, int indent write(ts, *child, indent + 1); } -void writeSVGResource(TextStream& ts, const RenderObject& object, int indent) +static inline String boundingBoxModeString(bool boundingBoxMode) +{ + return boundingBoxMode ? "objectBoundingBox" : "userSpaceOnUse"; +} + +static inline void writeCommonGradientProperties(TextStream& ts, GradientSpreadMethod spreadMethod, const AffineTransform& gradientTransform, bool boundingBoxMode) +{ + writeNameValuePair(ts, "gradientUnits", boundingBoxModeString(boundingBoxMode)); + + if (spreadMethod != SpreadMethodPad) + ts << " [spreadMethod=" << spreadMethod << "]"; + + if (!gradientTransform.isIdentity()) + ts << " [gradientTransform=" << gradientTransform << "]"; +} + +void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int indent) { writeStandardPrefix(ts, object, indent); @@ -523,16 +589,16 @@ void writeSVGResource(TextStream& ts, const RenderObject& object, int indent) const AtomicString& id = element->getIDAttribute(); writeNameAndQuotedValue(ts, "id", id); - RenderSVGResource* resource = const_cast<RenderObject&>(object).toRenderSVGResource(); + RenderSVGResourceContainer* resource = const_cast<RenderObject&>(object).toRenderSVGResourceContainer(); + ASSERT(resource); + if (resource->resourceType() == MaskerResourceType) { RenderSVGResourceMasker* masker = static_cast<RenderSVGResourceMasker*>(resource); - ASSERT(masker); writeNameValuePair(ts, "maskUnits", masker->maskUnits()); writeNameValuePair(ts, "maskContentUnits", masker->maskContentUnits()); #if ENABLE(FILTERS) } else if (resource->resourceType() == FilterResourceType) { RenderSVGResourceFilter* filter = static_cast<RenderSVGResourceFilter*>(resource); - ASSERT(filter); writeNameValuePair(ts, "filterUnits", filter->filterUnits()); writeNameValuePair(ts, "primitiveUnits", filter->primitiveUnits()); if (OwnPtr<SVGFilterBuilder> builder = filter->buildPrimitives()) { @@ -558,11 +624,9 @@ void writeSVGResource(TextStream& ts, const RenderObject& object, int indent) #endif } else if (resource->resourceType() == ClipperResourceType) { RenderSVGResourceClipper* clipper = static_cast<RenderSVGResourceClipper*>(resource); - ASSERT(clipper); writeNameValuePair(ts, "clipPathUnits", clipper->clipPathUnits()); } else if (resource->resourceType() == MarkerResourceType) { RenderSVGResourceMarker* marker = static_cast<RenderSVGResourceMarker*>(resource); - ASSERT(marker); writeNameValuePair(ts, "markerUnits", marker->markerUnits()); ts << " [ref at " << marker->referencePoint() << "]"; ts << " [angle="; @@ -570,6 +634,49 @@ void writeSVGResource(TextStream& ts, const RenderObject& object, int indent) ts << "auto" << "]"; else ts << marker->angle() << "]"; + } else if (resource->resourceType() == PatternResourceType) { + RenderSVGResourcePattern* pattern = static_cast<RenderSVGResourcePattern*>(resource); + + // Dump final results that are used for rendering. No use in asking SVGPatternElement for its patternUnits(), as it may + // link to other patterns using xlink:href, we need to build the full inheritance chain, aka. collectPatternProperties() + PatternAttributes attributes = static_cast<SVGPatternElement*>(pattern->node())->collectPatternProperties(); + writeNameValuePair(ts, "patternUnits", boundingBoxModeString(attributes.boundingBoxMode())); + writeNameValuePair(ts, "patternContentUnits", boundingBoxModeString(attributes.boundingBoxModeContent())); + + AffineTransform transform = attributes.patternTransform(); + if (!transform.isIdentity()) + ts << " [patternTransform=" << transform << "]"; + } else if (resource->resourceType() == LinearGradientResourceType) { + RenderSVGResourceLinearGradient* gradient = static_cast<RenderSVGResourceLinearGradient*>(resource); + + // Dump final results that are used for rendering. No use in asking SVGGradientElement for its gradientUnits(), as it may + // link to other gradients using xlink:href, we need to build the full inheritance chain, aka. collectGradientProperties() + SVGLinearGradientElement* linearGradientElement = static_cast<SVGLinearGradientElement*>(gradient->node()); + + LinearGradientAttributes attributes = linearGradientElement->collectGradientProperties(); + writeCommonGradientProperties(ts, attributes.spreadMethod(), attributes.gradientTransform(), attributes.boundingBoxMode()); + + FloatPoint startPoint; + FloatPoint endPoint; + linearGradientElement->calculateStartEndPoints(attributes, startPoint, endPoint); + + ts << " [start=" << startPoint << "] [end=" << endPoint << "]"; + } else if (resource->resourceType() == RadialGradientResourceType) { + RenderSVGResourceRadialGradient* gradient = static_cast<RenderSVGResourceRadialGradient*>(resource); + + // Dump final results that are used for rendering. No use in asking SVGGradientElement for its gradientUnits(), as it may + // link to other gradients using xlink:href, we need to build the full inheritance chain, aka. collectGradientProperties() + SVGRadialGradientElement* radialGradientElement = static_cast<SVGRadialGradientElement*>(gradient->node()); + + RadialGradientAttributes attributes = radialGradientElement->collectGradientProperties(); + writeCommonGradientProperties(ts, attributes.spreadMethod(), attributes.gradientTransform(), attributes.boundingBoxMode()); + + FloatPoint focalPoint; + FloatPoint centerPoint; + float radius; + radialGradientElement->calculateFocalCenterPointsAndRadius(attributes, focalPoint, centerPoint, radius); + + ts << " [center=" << centerPoint << "] [focal=" << focalPoint << "] [radius=" << radius << "]"; } ts << "\n"; @@ -626,6 +733,20 @@ void write(TextStream& ts, const RenderPath& path, int indent) writeResources(ts, path, indent); } +void writeSVGGradientStop(TextStream& ts, const RenderSVGGradientStop& stop, int indent) +{ + writeStandardPrefix(ts, stop, indent); + + SVGStopElement* stopElement = static_cast<SVGStopElement*>(stop.node()); + ASSERT(stopElement); + + RenderStyle* style = stop.style(); + if (!style) + return; + + ts << " [offset=" << stopElement->offset() << "] [color=" << stopElement->stopColorIncludingOpacity() << "]\n"; +} + void writeResources(TextStream& ts, const RenderObject& object, int indent) { const RenderStyle* style = object.style(); @@ -665,31 +786,6 @@ void writeResources(TextStream& ts, const RenderObject& object, int indent) #endif } -void writeRenderResources(TextStream& ts, Node* parent) -{ - ASSERT(parent); - Node* node = parent; - do { - if (!node->isSVGElement()) - continue; - SVGElement* svgElement = static_cast<SVGElement*>(node); - if (!svgElement->isStyled()) - continue; - - SVGStyledElement* styled = static_cast<SVGStyledElement*>(svgElement); - RefPtr<SVGResource> resource(styled->canvasResource(node->renderer())); - if (!resource) - continue; - - String elementId = svgElement->getAttribute(svgElement->idAttributeName()); - // FIXME: These names are lies! - if (resource->isPaintServer()) { - RefPtr<SVGPaintServer> paintServer = WTF::static_pointer_cast<SVGPaintServer>(resource); - ts << "KRenderingPaintServer {id=\"" << elementId << "\" " << *paintServer << "}" << "\n"; - } - } while ((node = node->traverseNextNode(parent))); -} - } // namespace WebCore #endif // ENABLE(SVG) diff --git a/WebCore/rendering/SVGRenderTreeAsText.h b/WebCore/rendering/SVGRenderTreeAsText.h index 905652b..0fda958 100644 --- a/WebCore/rendering/SVGRenderTreeAsText.h +++ b/WebCore/rendering/SVGRenderTreeAsText.h @@ -43,6 +43,7 @@ namespace WebCore { class RenderImage; class RenderObject; class RenderPath; + class RenderSVGGradientStop; class RenderSVGRoot; class RenderText; class AffineTransform; @@ -51,15 +52,14 @@ namespace WebCore { // functions used by the main RenderTreeAsText code void write(TextStream&, const RenderPath&, int indent); void write(TextStream&, const RenderSVGRoot&, int indent); -void writeSVGResource(TextStream&, const RenderObject&, int indent); +void writeSVGGradientStop(TextStream&, const RenderSVGGradientStop&, int indent); +void writeSVGResourceContainer(TextStream&, const RenderObject&, 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 writeResources(TextStream&, const RenderObject&, int indent); -void writeRenderResources(TextStream&, Node* parent); - // helper operators defined used in various classes to dump the render tree. TextStream& operator<<(TextStream&, const AffineTransform&); TextStream& operator<<(TextStream&, const IntRect&); diff --git a/WebCore/rendering/SVGRootInlineBox.cpp b/WebCore/rendering/SVGRootInlineBox.cpp index 89b4375..6c99b1a 100644 --- a/WebCore/rendering/SVGRootInlineBox.cpp +++ b/WebCore/rendering/SVGRootInlineBox.cpp @@ -4,6 +4,7 @@ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> * (C) 2006 Apple Computer Inc. * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. 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,12 +33,12 @@ #include "Frame.h" #include "GraphicsContext.h" #include "RenderBlock.h" +#include "RenderSVGResource.h" #include "RenderSVGResourceFilter.h" #include "RenderSVGRoot.h" #include "SVGInlineFlowBox.h" #include "SVGInlineTextBox.h" #include "SVGFontElement.h" -#include "SVGPaintServer.h" #include "SVGRenderStyleDefs.h" #include "SVGRenderSupport.h" #include "SVGTextPositioningElement.h" @@ -319,7 +320,7 @@ FloatPoint topLeftPositionOfCharacterRange(Vector<SVGChar>::iterator it, Vector< } // Helper function -static float calculateKerning(RenderObject* item) +static float calculateCSSKerning(RenderObject* item) { const Font& font = item->style()->font(); const SVGRenderStyle* svgStyle = item->style()->svgStyle(); @@ -335,6 +336,40 @@ static float calculateKerning(RenderObject* item) return kerning; } +static bool applySVGKerning(SVGCharacterLayoutInfo& info, RenderObject* item, LastGlyphInfo& lastGlyph, const String& unicodeString, const String& glyphName) +{ +#if ENABLE(SVG_FONTS) + float kerning = 0.0f; + const RenderStyle* style = item->style(); + SVGFontElement* svgFont = 0; + if (style->font().isSVGFont()) + svgFont = style->font().svgFont(); + + if (lastGlyph.isValid && style->font().isSVGFont()) + kerning = svgFont->getHorizontalKerningPairForStringsAndGlyphs(lastGlyph.unicode, lastGlyph.glyphName, unicodeString, glyphName); + + if (style->font().isSVGFont()) { + lastGlyph.unicode = unicodeString; + lastGlyph.glyphName = glyphName; + lastGlyph.isValid = true; + kerning *= style->font().size() / style->font().primaryFont()->unitsPerEm(); + } else + lastGlyph.isValid = false; + + if (kerning != 0.0f) { + info.curx -= kerning; + return true; + } +#else + UNUSED_PARAM(info); + UNUSED_PARAM(item); + UNUSED_PARAM(lastGlyph); + UNUSED_PARAM(unicodeString); + UNUSED_PARAM(glyphName); +#endif + return false; +} + // Helper class for paint() struct SVGRootInlineBoxPaintWalker { SVGRootInlineBoxPaintWalker(SVGRootInlineBox* rootBox, RenderSVGResourceFilter* rootFilter, RenderObject::PaintInfo paintInfo, int tx, int ty) @@ -345,10 +380,10 @@ struct SVGRootInlineBoxPaintWalker { , m_boundingBox(tx + rootBox->x(), ty + rootBox->y(), rootBox->width(), rootBox->height()) , m_filter(0) , m_rootFilter(rootFilter) - , m_fillPaintServer(0) - , m_strokePaintServer(0) - , m_fillPaintServerObject(0) - , m_strokePaintServerObject(0) + , m_fillPaintingResource(0) + , m_strokePaintingResource(0) + , m_fillPaintingResourceObject(0) + , m_strokePaintingResourceObject(0) , m_tx(tx) , m_ty(ty) { @@ -357,10 +392,10 @@ struct SVGRootInlineBoxPaintWalker { ~SVGRootInlineBoxPaintWalker() { ASSERT(!m_filter); - ASSERT(!m_fillPaintServer); - ASSERT(!m_fillPaintServerObject); - ASSERT(!m_strokePaintServer); - ASSERT(!m_strokePaintServerObject); + ASSERT(!m_fillPaintingResource); + ASSERT(!m_fillPaintingResourceObject); + ASSERT(!m_strokePaintingResource); + ASSERT(!m_strokePaintingResourceObject); ASSERT(!m_chunkStarted); } @@ -373,24 +408,22 @@ struct SVGRootInlineBoxPaintWalker { void teardownFillPaintServer() { - if (!m_fillPaintServer) + if (!m_fillPaintingResource) return; - m_fillPaintServer->teardown(m_paintInfo.context, m_fillPaintServerObject, ApplyToFillTargetType, true); - - m_fillPaintServer = 0; - m_fillPaintServerObject = 0; + m_fillPaintingResource->postApplyResource(m_fillPaintingResourceObject, m_paintInfo.context, ApplyToFillMode | ApplyToTextMode); + m_fillPaintingResource = 0; + m_fillPaintingResourceObject = 0; } void teardownStrokePaintServer() { - if (!m_strokePaintServer) + if (!m_strokePaintingResource) return; - m_strokePaintServer->teardown(m_paintInfo.context, m_strokePaintServerObject, ApplyToStrokeTargetType, true); - - m_strokePaintServer = 0; - m_strokePaintServerObject = 0; + m_strokePaintingResource->postApplyResource(m_strokePaintingResourceObject, m_paintInfo.context, ApplyToStrokeMode | ApplyToTextMode); + m_strokePaintingResource = 0; + m_strokePaintingResourceObject = 0; } void chunkStartCallback(InlineBox* box) @@ -437,7 +470,7 @@ struct SVGRootInlineBoxPaintWalker { m_paintInfo.rect = m_savedInfo.rect; } - bool setupBackground(SVGInlineTextBox* /*box*/) + bool setupBackground(SVGInlineTextBox*) { m_textPaintInfo.subphase = SVGTextPaintSubphaseBackground; return true; @@ -451,14 +484,14 @@ struct SVGRootInlineBoxPaintWalker { RenderObject* object = flowBox->renderer(); ASSERT(object); - ASSERT(!m_strokePaintServer); + ASSERT(!m_strokePaintingResource); teardownFillPaintServer(); m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphFill; - m_fillPaintServer = SVGPaintServer::fillPaintServer(object->style(), object); - if (m_fillPaintServer) { - m_fillPaintServer->setup(m_paintInfo.context, object, ApplyToFillTargetType, true); - m_fillPaintServerObject = object; + m_fillPaintingResource = RenderSVGResource::fillPaintingResource(object, object->style()); + if (m_fillPaintingResource) { + m_fillPaintingResource->applyResource(object, object->style(), m_paintInfo.context, ApplyToFillMode | ApplyToTextMode); + m_fillPaintingResourceObject = object; return true; } @@ -476,17 +509,17 @@ struct SVGRootInlineBoxPaintWalker { if (!style) style = object->style(); - ASSERT(!m_strokePaintServer); + ASSERT(!m_strokePaintingResource); teardownFillPaintServer(); if (!mayHaveSelection(box)) return false; m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphFillSelection; - m_fillPaintServer = SVGPaintServer::fillPaintServer(style, object); - if (m_fillPaintServer) { - m_fillPaintServer->setup(m_paintInfo.context, object, style, ApplyToFillTargetType, true); - m_fillPaintServerObject = object; + m_fillPaintingResource = RenderSVGResource::fillPaintingResource(object, style); + if (m_fillPaintingResource) { + m_fillPaintingResource->applyResource(object, style, m_paintInfo.context, ApplyToFillMode | ApplyToTextMode); + m_fillPaintingResourceObject = object; return true; } @@ -506,11 +539,10 @@ struct SVGRootInlineBoxPaintWalker { teardownStrokePaintServer(); m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphStroke; - m_strokePaintServer = SVGPaintServer::strokePaintServer(object->style(), object); - - if (m_strokePaintServer) { - m_strokePaintServer->setup(m_paintInfo.context, object, ApplyToStrokeTargetType, true); - m_strokePaintServerObject = object; + m_strokePaintingResource = RenderSVGResource::strokePaintingResource(object, object->style()); + if (m_strokePaintingResource) { + m_strokePaintingResource->applyResource(object, object->style(), m_paintInfo.context, ApplyToStrokeMode | ApplyToTextMode); + m_strokePaintingResourceObject = object; return true; } @@ -536,17 +568,17 @@ struct SVGRootInlineBoxPaintWalker { return false; m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphStrokeSelection; - m_strokePaintServer = SVGPaintServer::strokePaintServer(style, object); - if (m_strokePaintServer) { - m_strokePaintServer->setup(m_paintInfo.context, object, style, ApplyToStrokeTargetType, true); - m_strokePaintServerObject = object; + m_strokePaintingResource = RenderSVGResource::strokePaintingResource(object, style); + if (m_strokePaintingResource) { + m_strokePaintingResource->applyResource(object, style, m_paintInfo.context, ApplyToStrokeMode | ApplyToTextMode); + m_strokePaintingResourceObject = object; return true; } return false; } - bool setupForeground(SVGInlineTextBox* /*box*/) + bool setupForeground(SVGInlineTextBox*) { teardownFillPaintServer(); teardownStrokePaintServer(); @@ -556,17 +588,17 @@ struct SVGRootInlineBoxPaintWalker { return true; } - SVGPaintServer* activePaintServer() const + RenderSVGResource* activePaintingResource() const { switch (m_textPaintInfo.subphase) { case SVGTextPaintSubphaseGlyphFill: case SVGTextPaintSubphaseGlyphFillSelection: - ASSERT(m_fillPaintServer); - return m_fillPaintServer; + ASSERT(m_fillPaintingResource); + return m_fillPaintingResource; case SVGTextPaintSubphaseGlyphStroke: case SVGTextPaintSubphaseGlyphStrokeSelection: - ASSERT(m_strokePaintServer); - return m_strokePaintServer; + ASSERT(m_strokePaintingResource); + return m_strokePaintingResource; case SVGTextPaintSubphaseBackground: case SVGTextPaintSubphaseForeground: default: @@ -646,7 +678,7 @@ struct SVGRootInlineBoxPaintWalker { textBox->paintDecoration(OVERLINE, m_paintInfo.context, decorationOrigin.x(), decorationOrigin.y(), textWidth, *it, info); // Paint text - m_textPaintInfo.activePaintServer = activePaintServer(); + m_textPaintInfo.activePaintingResource = activePaintingResource(); textBox->paintCharacters(m_paintInfo, m_tx, m_ty, *it, stringStart, stringLength, m_textPaintInfo); // Paint decorations, that have to be drawn afterwards @@ -672,11 +704,11 @@ private: RenderSVGResourceFilter* m_filter; RenderSVGResourceFilter* m_rootFilter; - SVGPaintServer* m_fillPaintServer; - SVGPaintServer* m_strokePaintServer; + RenderSVGResource* m_fillPaintingResource; + RenderSVGResource* m_strokePaintingResource; - RenderObject* m_fillPaintServerObject; - RenderObject* m_strokePaintServerObject; + RenderObject* m_fillPaintingResourceObject; + RenderObject* m_strokePaintingResourceObject; int m_tx; int m_ty; @@ -1296,7 +1328,7 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo& } // Take letter & word spacing and kerning into account - float spacing = font.letterSpacing() + calculateKerning(textBox->renderer()->node()->renderer()); + float spacing = font.letterSpacing() + calculateCSSKerning(textBox->renderer()->node()->renderer()); const UChar* currentCharacter = text->characters() + (textBox->direction() == RTL ? textBox->end() - i : textBox->start() + i); const UChar* lastCharacter = 0; @@ -1309,7 +1341,9 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo& lastCharacter = text->characters() + textBox->start() + i - 1; } - if (info.nextDrawnSeperated || spacing != 0.0f) { + // FIXME: SVG Kerning doesn't get applied on texts on path. + bool appliedSVGKerning = applySVGKerning(info, textBox->renderer()->node()->renderer(), lastGlyph, unicodeStr, glyphName); + if (info.nextDrawnSeperated || spacing != 0.0f || appliedSVGKerning) { info.nextDrawnSeperated = false; svgChar.drawnSeperated = true; } @@ -1414,35 +1448,12 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo& } } - float kerning = 0.0f; -#if ENABLE(SVG_FONTS) - SVGFontElement* svgFont = 0; - if (style->font().isSVGFont()) - svgFont = style->font().svgFont(); - - if (lastGlyph.isValid && style->font().isSVGFont()) { - SVGHorizontalKerningPair kerningPair; - if (svgFont->getHorizontalKerningPairForStringsAndGlyphs(lastGlyph.unicode, lastGlyph.glyphName, unicodeStr, glyphName, kerningPair)) - kerning = narrowPrecisionToFloat(kerningPair.kerning); - } - - if (style->font().isSVGFont()) { - lastGlyph.unicode = unicodeStr; - lastGlyph.glyphName = glyphName; - lastGlyph.isValid = true; - kerning *= style->font().size() / style->font().primaryFont()->unitsPerEm(); - } else - lastGlyph.isValid = false; -#endif - - svgChar.x -= kerning; - // Advance to new position if (isVerticalText) { svgChar.drawnSeperated = true; info.cury += glyphAdvance + spacing; } else - info.curx += glyphAdvance + spacing - kerning; + info.curx += glyphAdvance + spacing; // Advance to next character group for (int k = 0; k < charsConsumed; ++k) { diff --git a/WebCore/rendering/SVGRootInlineBox.h b/WebCore/rendering/SVGRootInlineBox.h index 7b1dcc4..73c88a1 100644 --- a/WebCore/rendering/SVGRootInlineBox.h +++ b/WebCore/rendering/SVGRootInlineBox.h @@ -27,7 +27,9 @@ #if ENABLE(SVG) #include "RootInlineBox.h" +#include "SVGCharacterData.h" #include "SVGCharacterLayoutInfo.h" +#include "SVGTextChunkLayoutInfo.h" #include "SVGRenderSupport.h" namespace WebCore { @@ -51,7 +53,6 @@ public: , m_height(0) { } - virtual const SVGRenderBase* toSVGRenderBase() const { return this; } virtual bool isSVGRootInlineBox() { return true; } diff --git a/WebCore/rendering/SVGShadowTreeElements.cpp b/WebCore/rendering/SVGShadowTreeElements.cpp index d9ce640..f26f87e 100644 --- a/WebCore/rendering/SVGShadowTreeElements.cpp +++ b/WebCore/rendering/SVGShadowTreeElements.cpp @@ -49,7 +49,7 @@ SVGShadowTreeRootElement::SVGShadowTreeRootElement(Document* document, Node* sha : SVGShadowTreeContainerElement(document) , m_shadowParent(shadowParent) { - setInDocument(true); + setInDocument(); } SVGShadowTreeRootElement::~SVGShadowTreeRootElement() diff --git a/WebCore/rendering/SVGTextChunkLayoutInfo.h b/WebCore/rendering/SVGTextChunkLayoutInfo.h new file mode 100644 index 0000000..524c983 --- /dev/null +++ b/WebCore/rendering/SVGTextChunkLayoutInfo.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. 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 SVGTextChunkLayoutInfo_h +#define SVGTextChunkLayoutInfo_h + +#if ENABLE(SVG) +#include "AffineTransform.h" +#include "SVGTextContentElement.h" + +#include <wtf/Assertions.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class InlineBox; +class SVGInlineTextBox; + +struct SVGInlineBoxCharacterRange { + SVGInlineBoxCharacterRange() + : startOffset(INT_MIN) + , endOffset(INT_MIN) + , box(0) + { + } + + bool isOpen() const { return (startOffset == endOffset) && (endOffset == INT_MIN); } + bool isClosed() const { return startOffset != INT_MIN && endOffset != INT_MIN; } + + int startOffset; + int endOffset; + + InlineBox* box; +}; + +struct SVGChar; + +// Convenience typedef +typedef SVGTextContentElement::SVGLengthAdjustType ELengthAdjust; + +struct SVGTextChunk { + SVGTextChunk() + : anchor(TA_START) + , textLength(0.0f) + , lengthAdjust(SVGTextContentElement::LENGTHADJUST_SPACING) + , ctm() + , isVerticalText(false) + , isTextPath(false) + , start(0) + , end(0) + { } + + // text-anchor support + ETextAnchor anchor; + + // textLength & lengthAdjust support + float textLength; + ELengthAdjust lengthAdjust; + AffineTransform ctm; + + // status flags + bool isVerticalText : 1; + bool isTextPath : 1; + + // main chunk data + Vector<SVGChar>::iterator start; + Vector<SVGChar>::iterator end; + + Vector<SVGInlineBoxCharacterRange> boxes; +}; + +struct SVGTextChunkWalkerBase { + virtual ~SVGTextChunkWalkerBase() { } + + virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, + const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) = 0; + + // Followings methods are only used for painting text chunks + virtual void start(InlineBox*) = 0; + virtual void end(InlineBox*) = 0; +}; + +template<typename CallbackClass> +struct SVGTextChunkWalker : public SVGTextChunkWalkerBase { +public: + typedef void (CallbackClass::*SVGTextChunkWalkerCallback)(SVGInlineTextBox* textBox, + int startOffset, + const AffineTransform& chunkCtm, + const Vector<SVGChar>::iterator& start, + const Vector<SVGChar>::iterator& end); + + // These callbacks are only used for painting! + typedef void (CallbackClass::*SVGTextChunkStartCallback)(InlineBox* box); + typedef void (CallbackClass::*SVGTextChunkEndCallback)(InlineBox* box); + + SVGTextChunkWalker(CallbackClass* object, + SVGTextChunkWalkerCallback walker, + SVGTextChunkStartCallback start = 0, + SVGTextChunkEndCallback end = 0) + : m_object(object) + , m_walkerCallback(walker) + , m_startCallback(start) + , m_endCallback(end) + { + ASSERT(object); + ASSERT(walker); + } + + virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, + const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) + { + (*m_object.*m_walkerCallback)(textBox, startOffset, chunkCtm, start, end); + } + + // Followings methods are only used for painting text chunks + virtual void start(InlineBox* box) + { + if (m_startCallback) + (*m_object.*m_startCallback)(box); + else + ASSERT_NOT_REACHED(); + } + + virtual void end(InlineBox* box) + { + if (m_endCallback) + (*m_object.*m_endCallback)(box); + else + ASSERT_NOT_REACHED(); + } + +private: + CallbackClass* m_object; + SVGTextChunkWalkerCallback m_walkerCallback; + SVGTextChunkStartCallback m_startCallback; + SVGTextChunkEndCallback m_endCallback; +}; + +struct SVGTextChunkLayoutInfo { + SVGTextChunkLayoutInfo(Vector<SVGTextChunk>& textChunks) + : assignChunkProperties(true) + , handlingTextPath(false) + , svgTextChunks(textChunks) + , it(0) + { + } + + bool assignChunkProperties : 1; + bool handlingTextPath : 1; + + Vector<SVGTextChunk>& svgTextChunks; + Vector<SVGChar>::iterator it; + + SVGTextChunk chunk; +}; + +} // namespace WebCore + +#endif // ENABLE(SVG) +#endif // SVGTextChunkLayoutInfo_h diff --git a/WebCore/rendering/TextControlInnerElements.cpp b/WebCore/rendering/TextControlInnerElements.cpp index 4cd55c5..84f7c0f 100644 --- a/WebCore/rendering/TextControlInnerElements.cpp +++ b/WebCore/rendering/TextControlInnerElements.cpp @@ -96,7 +96,7 @@ void TextControlInnerElement::attachInnerElement(Node* parent, PassRefPtr<Render // Set these explicitly since this normally happens during an attach() setAttached(); - setInDocument(true); + setInDocument(); // For elements without a shadow parent, add the node to the DOM normally. if (!m_shadowParent) @@ -116,16 +116,9 @@ void TextControlInnerTextElement::defaultEventHandler(Event* evt) { // FIXME: In the future, we should add a way to have default event listeners. Then we would add one to the text field's inner div, and we wouldn't need this subclass. Node* shadowAncestor = shadowAncestorNode(); - if (shadowAncestor && shadowAncestor->renderer()) { - ASSERT(shadowAncestor->renderer()->isTextControl()); - if (evt->isBeforeTextInsertedEvent()) { - if (shadowAncestor->renderer()->isTextField()) - static_cast<HTMLInputElement*>(shadowAncestor)->defaultEventHandler(evt); - else - static_cast<HTMLTextAreaElement*>(shadowAncestor)->defaultEventHandler(evt); - } - if (evt->type() == eventNames().webkitEditableContentChangedEvent) - toRenderTextControl(shadowAncestor->renderer())->subtreeHasChanged(); + if (shadowAncestor) { + if (evt->isBeforeTextInsertedEvent() || evt->type() == eventNames().webkitEditableContentChangedEvent) + shadowAncestor->defaultEventHandler(evt); } if (!evt->defaultHandled()) HTMLDivElement::defaultEventHandler(evt); @@ -211,4 +204,62 @@ void SearchFieldCancelButtonElement::defaultEventHandler(Event* evt) HTMLDivElement::defaultEventHandler(evt); } +SpinButtonElement::SpinButtonElement(Document* doc, Node* shadowParent) + : TextControlInnerElement(doc, shadowParent) + , m_capturing(false) + , m_onUpButton(false) +{ +} + +void SpinButtonElement::defaultEventHandler(Event* evt) +{ + if (!evt->isMouseEvent()) { + if (!evt->defaultHandled()) + HTMLDivElement::defaultEventHandler(evt); + return; + } + const MouseEvent* mevt = static_cast<MouseEvent*>(evt); + if (mevt->button() != LeftButton) { + if (!evt->defaultHandled()) + HTMLDivElement::defaultEventHandler(evt); + return; + } + + HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); + IntPoint local = roundedIntPoint(renderBox()->absoluteToLocal(mevt->absoluteLocation(), false, true)); + if (evt->type() == eventNames().clickEvent) { + if (renderBox()->borderBoxRect().contains(local)) { + input->focus(); + input->select(); + if (local.y() < renderBox()->y() + renderBox()->height() / 2) + input->stepUpFromRenderer(1); + else + input->stepUpFromRenderer(-1); + evt->setDefaultHandled(); + } + } else if (evt->type() == eventNames().mousemoveEvent) { + if (renderBox()->borderBoxRect().contains(local)) { + if (!m_capturing) { + if (Frame* frame = document()->frame()) { + frame->eventHandler()->setCapturingMouseEventsNode(input); + m_capturing = true; + } + } + bool oldOnUpButton = m_onUpButton; + m_onUpButton = local.y() < renderBox()->y() + renderBox()->height() / 2; + if (m_onUpButton != oldOnUpButton) + renderer()->repaint(); + } else { + if (m_capturing) { + if (Frame* frame = document()->frame()) { + frame->eventHandler()->setCapturingMouseEventsNode(0); + m_capturing = false; + } + } + } + } + if (!evt->defaultHandled()) + HTMLDivElement::defaultEventHandler(evt); +} + } diff --git a/WebCore/rendering/TextControlInnerElements.h b/WebCore/rendering/TextControlInnerElements.h index f72ddf2..f59ac96 100644 --- a/WebCore/rendering/TextControlInnerElements.h +++ b/WebCore/rendering/TextControlInnerElements.h @@ -68,6 +68,21 @@ private: bool m_capturing; }; +class SpinButtonElement : public TextControlInnerElement { +public: + SpinButtonElement(Document*, Node*); + virtual bool isSpinButtonElement() const { return true; } + virtual bool isEnabledFormControl() { return static_cast<Element*>(shadowAncestorNode())->isEnabledFormControl(); } + virtual void defaultEventHandler(Event*); + + bool onUpButton() const { return m_onUpButton; } + static const AtomicString& spinButtonNodeName(); + +private: + bool m_capturing; + bool m_onUpButton; +}; + } //namespace #endif diff --git a/WebCore/rendering/style/RenderStyle.cpp b/WebCore/rendering/style/RenderStyle.cpp index f1cf0bc..f3b3f0c 100644 --- a/WebCore/rendering/style/RenderStyle.cpp +++ b/WebCore/rendering/style/RenderStyle.cpp @@ -58,7 +58,7 @@ PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other) return adoptRef(new RenderStyle(*other)); } -RenderStyle::RenderStyle() +ALWAYS_INLINE RenderStyle::RenderStyle() : m_affectedByAttributeSelectors(false) , m_unique(false) , m_affectedByEmpty(false) @@ -85,7 +85,7 @@ RenderStyle::RenderStyle() setBitDefaults(); // Would it be faster to copy this from the default style? } -RenderStyle::RenderStyle(bool) +ALWAYS_INLINE RenderStyle::RenderStyle(bool) : m_affectedByAttributeSelectors(false) , m_unique(false) , m_affectedByEmpty(false) @@ -118,7 +118,7 @@ RenderStyle::RenderStyle(bool) #endif } -RenderStyle::RenderStyle(const RenderStyle& o) +ALWAYS_INLINE RenderStyle::RenderStyle(const RenderStyle& o) : RefCounted<RenderStyle>() , m_affectedByAttributeSelectors(false) , m_unique(false) diff --git a/WebCore/rendering/style/RenderStyle.h b/WebCore/rendering/style/RenderStyle.h index fe42339..815fb30 100644 --- a/WebCore/rendering/style/RenderStyle.h +++ b/WebCore/rendering/style/RenderStyle.h @@ -302,7 +302,7 @@ protected: noninherited_flags._isLink = false; } -protected: +private: RenderStyle(); // used to create the default style. RenderStyle(bool); diff --git a/WebCore/rendering/style/RenderStyleConstants.h b/WebCore/rendering/style/RenderStyleConstants.h index b899d57..b6dce18 100644 --- a/WebCore/rendering/style/RenderStyleConstants.h +++ b/WebCore/rendering/style/RenderStyleConstants.h @@ -74,7 +74,7 @@ enum PseudoId { MEDIA_CONTROLS_SEEK_BACK_BUTTON, MEDIA_CONTROLS_SEEK_FORWARD_BUTTON, MEDIA_CONTROLS_FULLSCREEN_BUTTON, MEDIA_CONTROLS_REWIND_BUTTON, MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON, MEDIA_CONTROLS_STATUS_DISPLAY, SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER, - INPUT_LIST_BUTTON, INNER_SPIN_BUTTON, OUTER_SPIN_BUTTON, VISITED_LINK, + INPUT_LIST_BUTTON, INNER_SPIN_BUTTON, OUTER_SPIN_BUTTON, VISITED_LINK, PROGRESS_BAR_VALUE, AFTER_LAST_INTERNAL_PSEUDOID, FIRST_PUBLIC_PSEUDOID = FIRST_LINE, diff --git a/WebCore/rendering/style/SVGRenderStyle.h b/WebCore/rendering/style/SVGRenderStyle.h index c6d5022..3d6a7da 100644 --- a/WebCore/rendering/style/SVGRenderStyle.h +++ b/WebCore/rendering/style/SVGRenderStyle.h @@ -108,8 +108,9 @@ public: SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, inheritedResources, markerEnd, MarkerEndResource, markerEndResource, String()) // convenience - bool hasStroke() const { return (strokePaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); } - bool hasFill() const { return (fillPaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); } + bool hasMarkers() const { return !markerStartResource().isEmpty() || !markerMidResource().isEmpty() || !markerEndResource().isEmpty(); } + bool hasStroke() const { return strokePaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE; } + bool hasFill() const { return fillPaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE; } static float cssPrimitiveToLength(const RenderObject*, CSSValue*, float defaultValue = 0.0f); diff --git a/WebCore/rendering/style/StyleRareInheritedData.h b/WebCore/rendering/style/StyleRareInheritedData.h index 1aa7b05..8f128fd 100644 --- a/WebCore/rendering/style/StyleRareInheritedData.h +++ b/WebCore/rendering/style/StyleRareInheritedData.h @@ -32,7 +32,7 @@ namespace WebCore { -struct ShadowData; +class ShadowData; // This struct is for rarely used inherited CSS3, CSS2, and WebKit-specific properties. // By grouping them together, we save space, and only allocate this object when someone diff --git a/WebCore/rendering/style/StyleRareNonInheritedData.h b/WebCore/rendering/style/StyleRareNonInheritedData.h index 452b273..21bbe94 100644 --- a/WebCore/rendering/style/StyleRareNonInheritedData.h +++ b/WebCore/rendering/style/StyleRareNonInheritedData.h @@ -40,13 +40,14 @@ namespace WebCore { class AnimationList; class CSSStyleSelector; +class ShadowData; class StyleFlexibleBoxData; class StyleMarqueeData; class StyleMultiColData; class StyleReflection; class StyleTransformData; + struct ContentData; -struct ShadowData; #if ENABLE(DASHBOARD_SUPPORT) class StyleDashboardRegion; |