diff options
Diffstat (limited to 'WebCore/rendering')
50 files changed, 727 insertions, 273 deletions
diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp index c97d965..1b855d4 100644 --- a/WebCore/rendering/RenderBlock.cpp +++ b/WebCore/rendering/RenderBlock.cpp @@ -3,6 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2007 David Smith (catfish.man@gmail.com) * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * 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 @@ -940,6 +941,10 @@ static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObje || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation()))) return false; + // FIXME: This check isn't required when inline run-ins can't be split into continuations. + if (prev && prev->firstChild() && prev->firstChild()->isInline() && prev->firstChild()->isRunIn()) + return false; + #if ENABLE(RUBY) if ((prev && (prev->isRubyRun() || prev->isRubyBase())) || (next && (next->isRubyRun() || next->isRubyBase()))) diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp index d4c691f..8d18440 100644 --- a/WebCore/rendering/RenderBox.cpp +++ b/WebCore/rendering/RenderBox.cpp @@ -3,7 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -155,7 +155,9 @@ void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyl if (isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition)) removeFloatingOrPositionedChildFromBlockLists(); } - } + } else if (newStyle && isBody()) + view()->repaint(); + if (FrameView *frameView = view()->frameView()) { bool newStyleIsFixed = newStyle && newStyle->position() == FixedPosition; bool oldStyleIsFixed = style() && style()->position() == FixedPosition; diff --git a/WebCore/rendering/RenderEmbeddedObject.cpp b/WebCore/rendering/RenderEmbeddedObject.cpp index de9ca17..e72825e 100644 --- a/WebCore/rendering/RenderEmbeddedObject.cpp +++ b/WebCore/rendering/RenderEmbeddedObject.cpp @@ -42,7 +42,7 @@ #include "MouseEvent.h" #include "Page.h" #include "Path.h" -#include "PluginWidget.h" +#include "PluginViewBase.h" #include "RenderTheme.h" #include "RenderView.h" #include "RenderWidgetProtector.h" @@ -53,10 +53,6 @@ #include "HTMLVideoElement.h" #endif -#if USE(ACCELERATED_COMPOSITING) -#include "PluginWidget.h" -#endif - namespace WebCore { using namespace HTMLNames; @@ -102,7 +98,7 @@ bool RenderEmbeddedObject::requiresLayer() const bool RenderEmbeddedObject::allowsAcceleratedCompositing() const { - return widget() && widget()->isPluginWidget() && static_cast<PluginWidget*>(widget())->platformLayer(); + return widget() && widget()->isPluginViewBase() && static_cast<PluginViewBase*>(widget())->platformLayer(); } #endif diff --git a/WebCore/rendering/RenderFileUploadControl.cpp b/WebCore/rendering/RenderFileUploadControl.cpp index c652276..f31ca20 100644 --- a/WebCore/rendering/RenderFileUploadControl.cpp +++ b/WebCore/rendering/RenderFileUploadControl.cpp @@ -94,10 +94,23 @@ void RenderFileUploadControl::valueChanged() bool RenderFileUploadControl::allowsMultipleFiles() { +#if ENABLE(DIRECTORY_UPLOAD) + if (allowsDirectoryUpload()) + return true; +#endif + HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); return !input->getAttribute(multipleAttr).isNull(); } +#if ENABLE(DIRECTORY_UPLOAD) +bool RenderFileUploadControl::allowsDirectoryUpload() +{ + HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); + return !input->getAttribute(webkitdirectoryAttr).isNull(); +} +#endif + String RenderFileUploadControl::acceptTypes() { return static_cast<HTMLInputElement*>(node())->accept(); diff --git a/WebCore/rendering/RenderFileUploadControl.h b/WebCore/rendering/RenderFileUploadControl.h index 25d2639..205ba47 100644 --- a/WebCore/rendering/RenderFileUploadControl.h +++ b/WebCore/rendering/RenderFileUploadControl.h @@ -62,6 +62,9 @@ private: void valueChanged(); void repaint() { RenderBlock::repaint(); } bool allowsMultipleFiles(); +#if ENABLE(DIRECTORY_UPLOAD) + bool allowsDirectoryUpload(); +#endif String acceptTypes(); void chooseIconForFiles(FileChooser*, const Vector<String>&); diff --git a/WebCore/rendering/RenderForeignObject.cpp b/WebCore/rendering/RenderForeignObject.cpp index 4b94bab..8b84f97 100644 --- a/WebCore/rendering/RenderForeignObject.cpp +++ b/WebCore/rendering/RenderForeignObject.cpp @@ -26,6 +26,7 @@ #include "RenderForeignObject.h" #include "GraphicsContext.h" +#include "RenderSVGResource.h" #include "RenderView.h" #include "SVGForeignObjectElement.h" #include "SVGRenderSupport.h" @@ -98,7 +99,7 @@ void RenderForeignObject::layout() ASSERT(needsLayout()); ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. - LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(node()); if (m_needsTransformUpdate) { @@ -118,6 +119,10 @@ void RenderForeignObject::layout() setLocation(roundedIntPoint(viewportLocation)); RenderBlock::layout(); + // Invalidate all resources of this client, if we changed something. + if (m_everHadLayout && selfNeedsLayout()) + RenderSVGResource::invalidateAllResourcesOfRenderer(this); + repainter.repaintAfterLayout(); setNeedsLayout(false); } diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp index 78fddfd..f0c6333 100644 --- a/WebCore/rendering/RenderLayer.cpp +++ b/WebCore/rendering/RenderLayer.cpp @@ -3761,7 +3761,7 @@ bool RenderLayer::shouldBeNormalFlowOnly() const static bool hasOverflowScroll(const RenderLayer* layer) { RenderBox* box = layer->renderBox(); - if (!box || !box->node()->hasTagName(HTMLNames::divTag)) + if (!box || !box->node() || !box->node()->hasTagName(HTMLNames::divTag)) return false; EOverflow x = box->style()->overflowX(); EOverflow y = box->style()->overflowY(); @@ -3933,7 +3933,7 @@ void showLayerTree(const WebCore::RenderLayer* layer) return; if (WebCore::Frame* frame = layer->renderer()->frame()) { - WebCore::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers | WebCore::RenderAsTextShowAddresses); + WebCore::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers | WebCore::RenderAsTextShowAddresses | WebCore::RenderAsTextShowIDAndClass); fprintf(stderr, "%s\n", output.utf8().data()); } } diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp index 1153727..2bc6a88 100644 --- a/WebCore/rendering/RenderLayerBacking.cpp +++ b/WebCore/rendering/RenderLayerBacking.cpp @@ -43,7 +43,7 @@ #include "HTMLNames.h" #include "InspectorTimelineAgent.h" #include "KeyframeList.h" -#include "PluginWidget.h" +#include "PluginViewBase.h" #include "RenderBox.h" #include "RenderIFrame.h" #include "RenderImage.h" @@ -68,6 +68,7 @@ using namespace HTMLNames; static bool hasBorderOutlineOrShadow(const RenderStyle*); static bool hasBoxDecorationsOrBackground(const RenderObject*); static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle*); +static IntRect clipBox(RenderBox* renderer); static inline bool is3DCanvas(RenderObject* renderer) { @@ -143,10 +144,60 @@ static bool hasNonZeroTransformOrigin(const RenderObject* renderer) || (style->transformOriginY().type() == Fixed && style->transformOriginY().value()); } +static RenderLayer* enclosingOverflowClipAncestor(RenderLayer* layer, bool& crossesTransform) +{ + crossesTransform = false; + + for (RenderLayer* curr = layer->parent(); curr; curr = curr->parent()) { + if (curr->renderer()->hasOverflowClip()) + return curr; + + if (curr->hasTransform()) + crossesTransform = true; + } + + return 0; +} + void RenderLayerBacking::updateCompositedBounds() { IntRect layerBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer); + // Clip to the size of the document or enclosing overflow-scroll layer. + if (compositor()->compositingConsultsOverlap() && !m_owningLayer->hasTransform()) { + bool crossesTransform; + RenderLayer* overflowAncestor = enclosingOverflowClipAncestor(m_owningLayer, crossesTransform); + // If an ancestor is transformed, we can't currently compute the correct rect to intersect with. + // We'd need RenderObject::convertContainerToLocalQuad(), which doesn't yet exist. + if (!crossesTransform) { + IntRect clippingBounds; + RenderLayer* boundsRelativeLayer; + + if (overflowAncestor) { + RenderBox* overflowBox = toRenderBox(overflowAncestor->renderer()); + // If scrollbars are visible, then constrain the layer to the scrollable area, so we can avoid redraws + // on scrolling. Otherwise just clip to the visible area (it can still be scrolled via JS, but we'll come + // back through this code when the scroll offset changes). + if (overflowBox->scrollsOverflow()) + clippingBounds = IntRect(-overflowAncestor->scrollXOffset(), -overflowAncestor->scrollYOffset(), overflowBox->scrollWidth(), overflowBox->scrollHeight()); + else + clippingBounds = clipBox(overflowBox); + + boundsRelativeLayer = overflowAncestor; + } else { + RenderView* view = m_owningLayer->renderer()->view(); + clippingBounds = view->layoutOverflowRect(); + boundsRelativeLayer = view->layer(); + } + + int deltaX = 0; + int deltaY = 0; + m_owningLayer->convertToLayerCoords(boundsRelativeLayer, deltaX, deltaY); + clippingBounds.move(-deltaX, -deltaY); + layerBounds.intersect(clippingBounds); + } + } + // If the element has a transform-origin that has fixed lengths, and the renderer has zero size, // then we need to ensure that the compositing layer has non-zero size so that we can apply // the transform-origin via the GraphicsLayer anchorPoint (which is expressed as a fractional value). @@ -215,8 +266,8 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() updateImageContents(); if (renderer()->isEmbeddedObject() && toRenderEmbeddedObject(renderer())->allowsAcceleratedCompositing()) { - PluginWidget* pluginWidget = static_cast<PluginWidget*>(toRenderEmbeddedObject(renderer())->widget()); - m_graphicsLayer->setContentsToMedia(pluginWidget->platformLayer()); + PluginViewBase* pluginViewBase = static_cast<PluginViewBase*>(toRenderEmbeddedObject(renderer())->widget()); + m_graphicsLayer->setContentsToMedia(pluginViewBase->platformLayer()); } #if ENABLE(VIDEO) else if (renderer()->isVideo()) { @@ -259,11 +310,11 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() // Set transform property, if it is not animating. We have to do this here because the transform // is affected by the layer dimensions. - if (!renderer()->animation()->isAnimatingPropertyOnRenderer(renderer(), CSSPropertyWebkitTransform)) + if (!renderer()->animation()->isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyWebkitTransform)) updateLayerTransform(renderer()->style()); // Set opacity, if it is not animating. - if (!renderer()->animation()->isAnimatingPropertyOnRenderer(renderer(), CSSPropertyOpacity)) + if (!renderer()->animation()->isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyOpacity)) updateLayerOpacity(renderer()->style()); RenderStyle* style = renderer()->style(); @@ -312,7 +363,12 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() } m_graphicsLayer->setPosition(FloatPoint() + (relativeCompositingBounds.location() - graphicsLayerParentLocation)); + + IntSize oldOffsetFromRenderer = m_graphicsLayer->offsetFromRenderer(); m_graphicsLayer->setOffsetFromRenderer(localCompositingBounds.location() - IntPoint()); + // If the compositing layer offset changes, we need to repaint. + if (oldOffsetFromRenderer != m_graphicsLayer->offsetFromRenderer()) + m_graphicsLayer->setNeedsDisplay(); FloatSize oldSize = m_graphicsLayer->size(); FloatSize newSize = relativeCompositingBounds.size(); @@ -961,38 +1017,11 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* bool shouldPaint = (m_owningLayer->hasVisibleContent() || m_owningLayer->hasVisibleDescendant()) && m_owningLayer->isSelfPaintingLayer(); if (shouldPaint && (paintingPhase & GraphicsLayerPaintBackground)) { - // If this is the root then we need to send in a bigger bounding box - // because we'll be painting the background as well (see RenderBox::paintRootBoxDecorations()). - IntRect paintBox = clipRectToApply; - - // FIXME: do we need this code? - if (renderer()->node() && renderer()->node()->isDocumentNode() && renderer()->document()->isHTMLDocument()) { - RenderBox* box = toRenderBox(renderer()); - int w = box->width(); - int h = box->height(); - - int rw; - int rh; - if (FrameView* frameView = box->view()->frameView()) { - rw = frameView->contentsWidth(); - rh = frameView->contentsHeight(); - } else { - rw = box->view()->width(); - rh = box->view()->height(); - } - - int bx = tx - box->marginLeft(); - int by = ty - box->marginTop(); - int bw = max(w + box->marginLeft() + box->marginRight() + box->borderLeft() + box->borderRight(), rw); - int bh = max(h + box->marginTop() + box->marginBottom() + box->borderTop() + box->borderBottom(), rh); - paintBox = IntRect(bx, by, bw, bh); - } - // Paint our background first, before painting any child layers. // Establish the clip used to paint our background. setClip(context, paintDirtyRect, damageRect); - PaintInfo info(context, paintBox, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0); + PaintInfo info(context, damageRect, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0); renderer()->paint(info, tx, ty); // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with @@ -1307,6 +1336,17 @@ String RenderLayerBacking::nameForLayer() const } #endif +CompositingLayerType RenderLayerBacking::compositingLayerType() const +{ + if (m_graphicsLayer->hasContentsLayer()) + return MediaCompositingLayer; + + if (m_graphicsLayer->drawsContent()) + return m_graphicsLayer->usingTiledLayer() ? TiledCompositingLayer : NormalCompositingLayer; + + return ContainerCompositingLayer; +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/rendering/RenderLayerBacking.h b/WebCore/rendering/RenderLayerBacking.h index 16c39da..852fc04 100644 --- a/WebCore/rendering/RenderLayerBacking.h +++ b/WebCore/rendering/RenderLayerBacking.h @@ -40,6 +40,13 @@ namespace WebCore { class KeyframeList; class RenderLayerCompositor; +enum CompositingLayerType { + NormalCompositingLayer, // non-tiled layer with backing store + TiledCompositingLayer, // tiled layer (always has backing store) + MediaCompositingLayer, // layer that contains an image, video, webGL or plugin + ContainerCompositingLayer // layer with no backing store +}; + // RenderLayerBacking controls the compositing behavior for a single RenderLayer. // It holds the various GraphicsLayers, and makes decisions about intra-layer rendering // optimizations. @@ -127,6 +134,9 @@ public: IntRect contentsBox() const; + // For informative purposes only. + CompositingLayerType compositingLayerType() const; + private: void createGraphicsLayer(); void destroyGraphicsLayer(); diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp index fe0d4e8..46278a2 100644 --- a/WebCore/rendering/RenderLayerCompositor.cpp +++ b/WebCore/rendering/RenderLayerCompositor.cpp @@ -643,9 +643,11 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O } } - // If we just entered compositing mode, the root will have become composited. - if (layer->isRootLayer() && inCompositingMode()) - willBeComposited = true; + // If we just entered compositing mode, the root will have become composited (as long as accelerated compositing is enabled). + if (layer->isRootLayer()) { + if (inCompositingMode() && m_hasAcceleratedCompositing) + willBeComposited = true; + } ASSERT(willBeComposited == needsToBeComposited(layer)); @@ -1337,8 +1339,8 @@ bool RenderLayerCompositor::requiresCompositingForIFrame(RenderObject* renderer) bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* renderer) const { if (AnimationController* animController = renderer->animation()) { - return (animController->isAnimatingPropertyOnRenderer(renderer, CSSPropertyOpacity) && inCompositingMode()) - || animController->isAnimatingPropertyOnRenderer(renderer, CSSPropertyWebkitTransform); + return (animController->isRunningAnimationOnRenderer(renderer, CSSPropertyOpacity) && inCompositingMode()) + || animController->isRunningAnimationOnRenderer(renderer, CSSPropertyWebkitTransform); } return false; } diff --git a/WebCore/rendering/RenderMenuList.cpp b/WebCore/rendering/RenderMenuList.cpp index 77fe3c2..177921c 100644 --- a/WebCore/rendering/RenderMenuList.cpp +++ b/WebCore/rendering/RenderMenuList.cpp @@ -26,7 +26,6 @@ #include "RenderMenuList.h" #include "AXObjectCache.h" -#include "AccessibilityObject.h" #include "CSSStyleSelector.h" #include "Frame.h" #include "FrameView.h" @@ -350,6 +349,11 @@ String RenderMenuList::itemText(unsigned listIndex) const return String(); } +String RenderMenuList::itemLabel(unsigned) const +{ + return String(); +} + String RenderMenuList::itemAccessibilityText(unsigned listIndex) const { // Allow the accessible name be changed if necessary. @@ -358,7 +362,7 @@ String RenderMenuList::itemAccessibilityText(unsigned listIndex) const if (listIndex >= listItems.size()) return String(); - return AccessibilityObject::getAttribute(listItems[listIndex], aria_labelAttr); + return listItems[listIndex]->getAttribute(aria_labelAttr); } String RenderMenuList::itemToolTip(unsigned listIndex) const diff --git a/WebCore/rendering/RenderMenuList.h b/WebCore/rendering/RenderMenuList.h index 9e51996..d72e1a9 100644 --- a/WebCore/rendering/RenderMenuList.h +++ b/WebCore/rendering/RenderMenuList.h @@ -82,6 +82,7 @@ private: // PopupMenuClient methods virtual String itemText(unsigned listIndex) const; + virtual String itemLabel(unsigned listIndex) const; virtual String itemToolTip(unsigned listIndex) const; virtual String itemAccessibilityText(unsigned listIndex) const; virtual bool itemIsEnabled(unsigned listIndex) const; diff --git a/WebCore/rendering/RenderObject.cpp b/WebCore/rendering/RenderObject.cpp index 4ff35eb..783ed63 100644 --- a/WebCore/rendering/RenderObject.cpp +++ b/WebCore/rendering/RenderObject.cpp @@ -944,10 +944,10 @@ void RenderObject::drawBoxSideFromPath(GraphicsContext* graphicsContext, IntRect whiteSpaceWidth += (patWidth / numberOfWhitespaceDashes); } - DashArray* lineDash = new DashArray(); - lineDash->append(patWidth); - lineDash->append(whiteSpaceWidth); - graphicsContext->setLineDash(*lineDash, patWidth); + DashArray lineDash; + lineDash.append(patWidth); + lineDash.append(whiteSpaceWidth); + graphicsContext->setLineDash(lineDash, patWidth); graphicsContext->addPath(borderPath); graphicsContext->strokePath(); return; @@ -1357,7 +1357,8 @@ bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintConta if (v->printing()) return false; // Don't repaint if we're printing. - ASSERT(!newBoundsPtr || *newBoundsPtr == clippedOverflowRectForRepaint(repaintContainer)); + // This ASSERT fails due to animations. See https://bugs.webkit.org/show_bug.cgi?id=37048 + // ASSERT(!newBoundsPtr || *newBoundsPtr == clippedOverflowRectForRepaint(repaintContainer)); IntRect newBounds = newBoundsPtr ? *newBoundsPtr : clippedOverflowRectForRepaint(repaintContainer); IntRect newOutlineBox; @@ -1366,7 +1367,8 @@ bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintConta if (!fullRepaint && style()->borderFit() == BorderFitLines) fullRepaint = true; if (!fullRepaint) { - ASSERT(!newOutlineBoxRectPtr || *newOutlineBoxRectPtr == outlineBoundsForRepaint(repaintContainer)); + // This ASSERT fails due to animations. See https://bugs.webkit.org/show_bug.cgi?id=37048 + // ASSERT(!newOutlineBoxRectPtr || *newOutlineBoxRectPtr == outlineBoundsForRepaint(repaintContainer)); newOutlineBox = newOutlineBoxRectPtr ? *newOutlineBoxRectPtr : outlineBoundsForRepaint(repaintContainer); if (newOutlineBox.location() != oldOutlineBox.location() || (mustRepaintBackgroundOrBorder() && (newBounds != oldBounds || newOutlineBox != oldOutlineBox))) fullRepaint = true; diff --git a/WebCore/rendering/RenderObjectChildList.cpp b/WebCore/rendering/RenderObjectChildList.cpp index 6775537..68e392c 100644 --- a/WebCore/rendering/RenderObjectChildList.cpp +++ b/WebCore/rendering/RenderObjectChildList.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -44,7 +45,11 @@ void RenderObjectChildList::destroyLeftoverChildren() while (firstChild()) { if (firstChild()->isListMarker() || (firstChild()->style()->styleType() == FIRST_LETTER && !firstChild()->isText())) firstChild()->remove(); // List markers are owned by their enclosing list and so don't get destroyed by this container. Similarly, first letters are destroyed by their remaining text fragment. - else { + else if (firstChild()->isRunIn() && firstChild()->node()) { + firstChild()->node()->setRenderer(0); + firstChild()->node()->setNeedsStyleRecalc(); + firstChild()->destroy(); + } else { // Destroy any anonymous children remaining in the render tree, as well as implicit (shadow) DOM elements like those used in the engine-based text fields. if (firstChild()->node()) firstChild()->node()->setRenderer(0); @@ -62,9 +67,12 @@ RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, Render // disappears gets repainted properly. if (!owner->documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) { oldChild->setNeedsLayoutAndPrefWidthsRecalc(); - oldChild->repaint(); + if (oldChild->isBody()) + owner->view()->repaint(); + else + oldChild->repaint(); } - + // If we have a line box wrapper, delete it. if (oldChild->isBox()) toRenderBox(oldChild)->deleteLineBoxWrapper(); diff --git a/WebCore/rendering/RenderPath.cpp b/WebCore/rendering/RenderPath.cpp index 27d480d..dd79397 100644 --- a/WebCore/rendering/RenderPath.cpp +++ b/WebCore/rendering/RenderPath.cpp @@ -97,7 +97,7 @@ bool RenderPath::strokeContains(const FloatPoint& point, bool requiresStroke) co void RenderPath::layout() { - LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout()); + LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node()); bool needsPathUpdate = m_needsPathUpdate; @@ -111,6 +111,10 @@ void RenderPath::layout() m_needsTransformUpdate = false; } + // Invalidate all resources of this client, if we changed something. + if (m_everHadLayout && selfNeedsLayout()) + RenderSVGResource::invalidateAllResourcesOfRenderer(this); + // At this point LayoutRepainter already grabbed the old bounds, // recalculate them now so repaintAfterLayout() uses the new bounds if (needsPathUpdate || m_needsBoundariesUpdate) { diff --git a/WebCore/rendering/RenderSVGContainer.cpp b/WebCore/rendering/RenderSVGContainer.cpp index d4ca69f..ad63771 100644 --- a/WebCore/rendering/RenderSVGContainer.cpp +++ b/WebCore/rendering/RenderSVGContainer.cpp @@ -27,6 +27,7 @@ #include "RenderSVGContainer.h" #include "GraphicsContext.h" +#include "RenderSVGResource.h" #include "RenderSVGResourceFilter.h" #include "RenderView.h" #include "SVGRenderSupport.h" @@ -50,13 +51,17 @@ void RenderSVGContainer::layout() // Allow RenderSVGViewportContainer to update its viewport. calcViewport(); - LayoutRepainter repainter(*this, checkForRepaintDuringLayout() || selfWillPaint()); + LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); // Allow RenderSVGTransformableContainer to update its transform. calculateLocalTransform(); SVGRenderSupport::layoutChildren(this, selfNeedsLayout()); + // Invalidate all resources of this client, if we changed something. + if (m_everHadLayout && selfNeedsLayout()) + RenderSVGResource::invalidateAllResourcesOfRenderer(this); + repainter.repaintAfterLayout(); setNeedsLayout(false); } diff --git a/WebCore/rendering/RenderSVGImage.cpp b/WebCore/rendering/RenderSVGImage.cpp index a4572e6..44b68b1 100644 --- a/WebCore/rendering/RenderSVGImage.cpp +++ b/WebCore/rendering/RenderSVGImage.cpp @@ -52,7 +52,7 @@ void RenderSVGImage::layout() { ASSERT(needsLayout()); - LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); SVGImageElement* image = static_cast<SVGImageElement*>(node()); if (m_needsTransformUpdate) { @@ -66,11 +66,15 @@ void RenderSVGImage::layout() calcWidth(); calcHeight(); + // FIXME: Optimize caching the repaint rects. m_localBounds = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image)); m_cachedLocalRepaintRect = FloatRect(); + // Invalidate all resources of this client, if we changed something. + if (m_everHadLayout && selfNeedsLayout()) + RenderSVGResource::invalidateAllResourcesOfRenderer(this); + repainter.repaintAfterLayout(); - setNeedsLayout(false); } diff --git a/WebCore/rendering/RenderSVGModelObject.cpp b/WebCore/rendering/RenderSVGModelObject.cpp index 3d22e7a..49404cb 100644 --- a/WebCore/rendering/RenderSVGModelObject.cpp +++ b/WebCore/rendering/RenderSVGModelObject.cpp @@ -87,6 +87,14 @@ void RenderSVGModelObject::destroy() RenderObject::destroy(); } +void RenderSVGModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderObject::styleDidChange(diff, oldStyle); + + if (style() && (diff == StyleDifferenceLayout || diff == StyleDifferenceRepaint)) + RenderSVGResource::markForLayoutAndParentResourceInvalidation(this, false); +} + bool RenderSVGModelObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) { ASSERT_NOT_REACHED(); diff --git a/WebCore/rendering/RenderSVGModelObject.h b/WebCore/rendering/RenderSVGModelObject.h index 82c08c0..741cd61 100644 --- a/WebCore/rendering/RenderSVGModelObject.h +++ b/WebCore/rendering/RenderSVGModelObject.h @@ -61,6 +61,7 @@ public: virtual void destroy(); virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); private: // This method should never be called, SVG uses a different nodeAtPoint method diff --git a/WebCore/rendering/RenderSVGResource.cpp b/WebCore/rendering/RenderSVGResource.cpp index 0aa7182..b4f499e 100644 --- a/WebCore/rendering/RenderSVGResource.cpp +++ b/WebCore/rendering/RenderSVGResource.cpp @@ -184,21 +184,17 @@ RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource() return s_sharedSolidPaintingResource; } -void RenderSVGResource::markForLayoutAndResourceInvalidation(RenderObject* object) +void RenderSVGResource::markForLayoutAndResourceInvalidation(RenderObject* object, bool needsBoundariesUpdate) { ASSERT(object); ASSERT(object->node()); ASSERT(object->node()->isSVGElement()); - // Mark the renderer for layout - object->setNeedsLayout(true); + // Eventually mark the renderer needing a boundaries update + if (needsBoundariesUpdate) + object->setNeedsBoundariesUpdate(); - // 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(); + markForLayoutAndParentResourceInvalidation(object); } static inline void invalidatePaintingResource(SVGPaint* paint, RenderObject* object) @@ -254,6 +250,22 @@ void RenderSVGResource::invalidateAllResourcesOfRenderer(RenderObject* object) invalidatePaintingResource(svgStyle->strokePaint(), object); } +void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject* object, bool needsLayout) +{ + ASSERT(object); + if (needsLayout) + object->setNeedsLayout(true); + + // Invalidate resources in ancestor chain, if needed. + RenderObject* current = object->parent(); + while (current) { + if (current->isSVGResourceContainer()) + current->toRenderSVGResourceContainer()->invalidateClients(); + + current = current->parent(); + } +} + } #endif diff --git a/WebCore/rendering/RenderSVGResource.h b/WebCore/rendering/RenderSVGResource.h index 34ff14e..b3ea6fb 100644 --- a/WebCore/rendering/RenderSVGResource.h +++ b/WebCore/rendering/RenderSVGResource.h @@ -80,12 +80,13 @@ public: static RenderSVGResourceSolidColor* sharedSolidPaintingResource(); static void invalidateAllResourcesOfRenderer(RenderObject*); + static void markForLayoutAndParentResourceInvalidation(RenderObject*, bool needsLayout = true); private: static void adjustColorForPseudoRules(const RenderStyle*, bool useFillPaint, Color&); protected: - void markForLayoutAndResourceInvalidation(RenderObject*); + void markForLayoutAndResourceInvalidation(RenderObject*, bool needsBoundariesUpdate = true); }; } diff --git a/WebCore/rendering/RenderSVGResourceClipper.cpp b/WebCore/rendering/RenderSVGResourceClipper.cpp index cc499bf..e923f7e 100644 --- a/WebCore/rendering/RenderSVGResourceClipper.cpp +++ b/WebCore/rendering/RenderSVGResourceClipper.cpp @@ -49,6 +49,7 @@ RenderSVGResourceType RenderSVGResourceClipper::s_resourceType = ClipperResource RenderSVGResourceClipper::RenderSVGResourceClipper(SVGClipPathElement* node) : RenderSVGResourceContainer(node) + , m_invalidationBlocked(false) { } @@ -60,12 +61,13 @@ RenderSVGResourceClipper::~RenderSVGResourceClipper() void RenderSVGResourceClipper::invalidateClients() { + if (m_invalidationBlocked) + return; + HashMap<RenderObject*, ClipperData*>::const_iterator end = m_clipper.end(); - for (HashMap<RenderObject*, ClipperData*>::const_iterator it = m_clipper.begin(); it != end; ++it) { - RenderObject* renderer = it->first; - renderer->setNeedsBoundariesUpdate(); - renderer->setNeedsLayout(true); - } + for (HashMap<RenderObject*, ClipperData*>::const_iterator it = m_clipper.begin(); it != end; ++it) + markForLayoutAndResourceInvalidation(it->first); + deleteAllValues(m_clipper); m_clipper.clear(); m_clipBoundaries = FloatRect(); @@ -73,12 +75,10 @@ void RenderSVGResourceClipper::invalidateClients() void RenderSVGResourceClipper::invalidateClient(RenderObject* object) { - ASSERT(object); + if (m_invalidationBlocked) + return; - // FIXME: The HashSet 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 + ASSERT(object); if (!m_clipper.contains(object)) return; @@ -95,6 +95,11 @@ bool RenderSVGResourceClipper::applyResource(RenderObject* object, RenderStyle*, #else UNUSED_PARAM(resourceMode); #endif + + // Early exit, if this resource contains a child which references ourselves. + if (containsCyclicReference(node())) + return false; + applyClippingToContext(object, object->objectBoundingBox(), object->repaintRectInLocalCoordinates(), context); return true; } @@ -237,6 +242,10 @@ bool RenderSVGResourceClipper::createClipData(ClipperData* clipperData, const Fl svgStyle->setStrokeOpacity(1.0f); svgStyle->setFilterResource(String()); svgStyle->setMaskerResource(String()); + + // The setStyle() call results in a styleDidChange() call, which in turn invalidations the resources. + // As we're mutating the resource on purpose, block updates until we've resetted the style again. + m_invalidationBlocked = true; renderer->setStyle(newRenderStyle.release()); // In the case of a <use> element, we obtained its renderere above, to retrieve its clipRule. @@ -245,6 +254,7 @@ bool RenderSVGResourceClipper::createClipData(ClipperData* clipperData, const Fl SVGRenderSupport::renderSubtreeToImage(clipperData->clipMaskImage.get(), isUseElement ? childNode->renderer() : renderer); renderer->setStyle(oldRenderStyle.release()); + m_invalidationBlocked = false; } maskContext->restore(); @@ -270,6 +280,12 @@ void RenderSVGResourceClipper::calculateClipContentRepaintRect() bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundingBox, const FloatPoint& nodeAtPoint) { + // FIXME: We should be able to check whether m_clipper.contains(object) - this doesn't work at the moment + // as resourceBoundingBox() has already created ClipperData, even if applyResource() returned false. + // Early exit, if this resource contains a child which references ourselves. + if (containsCyclicReference(node())) + return false; + FloatPoint point = nodeAtPoint; if (!SVGRenderSupport::pointInClippingArea(this, point)) return false; @@ -296,12 +312,16 @@ bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin return false; } -FloatRect RenderSVGResourceClipper::resourceBoundingBox(RenderObject* object) +bool RenderSVGResourceClipper::childElementReferencesResource(const SVGRenderStyle* style, const String& referenceId) const { - // Save the reference to the calling object for relayouting it on changing resource properties. - if (!m_clipper.contains(object)) - m_clipper.set(object, new ClipperData); + if (!style->hasClipper()) + return false; + + return style->clipperResource() == referenceId; +} +FloatRect RenderSVGResourceClipper::resourceBoundingBox(RenderObject* object) +{ // Resource was not layouted yet. Give back the boundingBox of the object. if (selfNeedsLayout()) return object->objectBoundingBox(); diff --git a/WebCore/rendering/RenderSVGResourceClipper.h b/WebCore/rendering/RenderSVGResourceClipper.h index 78ec75b..7128aa1 100644 --- a/WebCore/rendering/RenderSVGResourceClipper.h +++ b/WebCore/rendering/RenderSVGResourceClipper.h @@ -68,6 +68,9 @@ private: bool createClipData(ClipperData*, const FloatRect&, const FloatRect&); void calculateClipContentRepaintRect(); + virtual bool childElementReferencesResource(const SVGRenderStyle*, const String&) const; + + bool m_invalidationBlocked; FloatRect m_clipBoundaries; HashMap<RenderObject*, ClipperData*> m_clipper; }; diff --git a/WebCore/rendering/RenderSVGResourceContainer.h b/WebCore/rendering/RenderSVGResourceContainer.h index 54617bb..5f1c828 100644 --- a/WebCore/rendering/RenderSVGResourceContainer.h +++ b/WebCore/rendering/RenderSVGResourceContainer.h @@ -26,6 +26,7 @@ #include "SVGStyledTransformableElement.h" #include "RenderSVGResource.h" +#include "RenderSVGShadowTreeRootContainer.h" namespace WebCore { @@ -35,8 +36,7 @@ public: RenderSVGResourceContainer(SVGStyledElement* node) : RenderSVGHiddenContainer(node) , RenderSVGResource() - // FIXME: Should probably be using getIdAttribute rather than idForStyleResolution. - , m_id(node->hasID() ? node->idForStyleResolution() : nullAtom) + , m_id(node->hasID() ? node->getIdAttribute() : nullAtom) { ASSERT(node->document()); node->document()->accessSVGExtensions()->addResource(m_id, this); @@ -57,9 +57,7 @@ public: // Remove old id, that is guaranteed to be present in cache extensions->removeResource(m_id); - - // FIXME: Should probably be using getIdAttribute rather than idForStyleResolution. - m_id = node()->hasID() ? static_cast<Element*>(node())->idForStyleResolution() : nullAtom; + 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)) { @@ -84,7 +82,8 @@ public: virtual bool drawsContents() { return false; } virtual RenderSVGResourceContainer* toRenderSVGResourceContainer() { return this; } - + virtual bool childElementReferencesResource(const SVGRenderStyle*, const String&) const { return false; } + static AffineTransform transformOnNonScalingStroke(RenderObject* object, const AffineTransform resourceTransform) { if (!object->isRenderPath()) @@ -96,6 +95,48 @@ public: return transform; } + bool containsCyclicReference(const Node* startNode) const + { + ASSERT(startNode->document()); + + for (Node* node = startNode->firstChild(); node; node = node->nextSibling()) { + if (!node->isSVGElement()) + continue; + + RenderObject* renderer = node->renderer(); + if (!renderer) + continue; + + RenderStyle* style = renderer->style(); + if (!style) + continue; + + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + + // Let the class inheriting from us decide whether the child element references ourselves. + if (childElementReferencesResource(svgStyle, m_id)) + return true; + + // Dive into shadow tree to check for cycles there. + if (node->hasTagName(SVGNames::useTag)) { + ASSERT(renderer->isSVGShadowTreeRootContainer()); + if (Node* shadowRoot = static_cast<RenderSVGShadowTreeRootContainer*>(renderer)->rootElement()) { + if (containsCyclicReference(shadowRoot)) + return true; + } + + } + + if (node->hasChildNodes()) { + if (containsCyclicReference(node)) + return true; + } + } + + return false; + } + private: AtomicString m_id; }; diff --git a/WebCore/rendering/RenderSVGResourceFilter.cpp b/WebCore/rendering/RenderSVGResourceFilter.cpp index 19a6ccb..a6358f0 100644 --- a/WebCore/rendering/RenderSVGResourceFilter.cpp +++ b/WebCore/rendering/RenderSVGResourceFilter.cpp @@ -67,11 +67,9 @@ RenderSVGResourceFilter::~RenderSVGResourceFilter() void RenderSVGResourceFilter::invalidateClients() { HashMap<RenderObject*, FilterData*>::const_iterator end = m_filter.end(); - for (HashMap<RenderObject*, FilterData*>::const_iterator it = m_filter.begin(); it != end; ++it) { - RenderObject* renderer = it->first; - renderer->setNeedsBoundariesUpdate(); - renderer->setNeedsLayout(true); - } + for (HashMap<RenderObject*, FilterData*>::const_iterator it = m_filter.begin(); it != end; ++it) + markForLayoutAndResourceInvalidation(it->first); + deleteAllValues(m_filter); m_filter.clear(); } @@ -79,11 +77,6 @@ void RenderSVGResourceFilter::invalidateClients() void RenderSVGResourceFilter::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_filter.contains(object)) return; diff --git a/WebCore/rendering/RenderSVGResourceGradient.cpp b/WebCore/rendering/RenderSVGResourceGradient.cpp index 74f5b13..ce51369 100644 --- a/WebCore/rendering/RenderSVGResourceGradient.cpp +++ b/WebCore/rendering/RenderSVGResourceGradient.cpp @@ -51,7 +51,7 @@ 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); + markForLayoutAndResourceInvalidation(it->first, false); deleteAllValues(m_gradient); m_gradient.clear(); @@ -60,16 +60,11 @@ void RenderSVGResourceGradient::invalidateClients() 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); + markForLayoutAndResourceInvalidation(object, false); } #if PLATFORM(CG) @@ -133,7 +128,7 @@ static inline AffineTransform clipToTextMask(GraphicsContext* context, matrix.translate(maskBoundingBox.x(), maskBoundingBox.y()); matrix.scaleNonUniform(maskBoundingBox.width(), maskBoundingBox.height()); } - matrix.multiply(gradientData->transform); + matrix.multLeft(gradientData->transform); return matrix; } #endif @@ -179,7 +174,7 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle* gradientData->userspaceTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); } - gradientData->userspaceTransform.multiply(gradientData->transform); + gradientData->userspaceTransform.multLeft(gradientData->transform); gradientData->gradient->setGradientSpaceTransform(gradientData->userspaceTransform); } diff --git a/WebCore/rendering/RenderSVGResourceMarker.cpp b/WebCore/rendering/RenderSVGResourceMarker.cpp index ce331a7..4f0cace 100644 --- a/WebCore/rendering/RenderSVGResourceMarker.cpp +++ b/WebCore/rendering/RenderSVGResourceMarker.cpp @@ -62,11 +62,8 @@ void RenderSVGResourceMarker::addClient(const RenderObject* object) void RenderSVGResourceMarker::invalidateClients() { const HashSet<const RenderObject*>::const_iterator end = m_marker.end(); - for (HashSet<const RenderObject*>::const_iterator it = m_marker.begin(); it != end; ++it) { - RenderObject* renderer = const_cast<RenderObject*>(*it); - renderer->setNeedsBoundariesUpdate(); - renderer->setNeedsLayout(true); - } + for (HashSet<const RenderObject*>::const_iterator it = m_marker.begin(); it != end; ++it) + markForLayoutAndResourceInvalidation(const_cast<RenderObject*>(*it)); m_marker.clear(); } @@ -74,11 +71,6 @@ void RenderSVGResourceMarker::invalidateClients() void RenderSVGResourceMarker::invalidateClient(RenderObject* object) { ASSERT(object); - - // FIXME: The HashSet 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_marker.contains(object)) return; diff --git a/WebCore/rendering/RenderSVGResourceMasker.cpp b/WebCore/rendering/RenderSVGResourceMasker.cpp index 74d3fe6..83a64b5 100644 --- a/WebCore/rendering/RenderSVGResourceMasker.cpp +++ b/WebCore/rendering/RenderSVGResourceMasker.cpp @@ -58,11 +58,8 @@ RenderSVGResourceMasker::~RenderSVGResourceMasker() void RenderSVGResourceMasker::invalidateClients() { HashMap<RenderObject*, MaskerData*>::const_iterator end = m_masker.end(); - for (HashMap<RenderObject*, MaskerData*>::const_iterator it = m_masker.begin(); it != end; ++it) { - RenderObject* renderer = it->first; - renderer->setNeedsBoundariesUpdate(); - renderer->setNeedsLayout(true); - } + for (HashMap<RenderObject*, MaskerData*>::const_iterator it = m_masker.begin(); it != end; ++it) + markForLayoutAndResourceInvalidation(it->first); deleteAllValues(m_masker); m_masker.clear(); @@ -72,11 +69,6 @@ void RenderSVGResourceMasker::invalidateClients() void RenderSVGResourceMasker::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_masker.contains(object)) return; @@ -84,6 +76,14 @@ void RenderSVGResourceMasker::invalidateClient(RenderObject* object) markForLayoutAndResourceInvalidation(object); } +bool RenderSVGResourceMasker::childElementReferencesResource(const SVGRenderStyle* style, const String& referenceId) const +{ + if (!style->hasMasker()) + return false; + + return style->maskerResource() == referenceId; +} + bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(object); @@ -103,6 +103,10 @@ bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, if (!maskElement) return false; + // Early exit, if this resource contains a child which references ourselves. + if (containsCyclicReference(node())) + return false; + createMaskImage(maskerData, maskElement, object); } @@ -178,6 +182,10 @@ void RenderSVGResourceMasker::createMaskImage(MaskerData* maskerData, const SVGM maskImageContext->restore(); +#if !PLATFORM(CG) + maskerData->maskImage->transformColorSpace(DeviceRGB, LinearRGB); +#endif + // create the luminance mask RefPtr<ImageData> imageData(maskerData->maskImage->getUnmultipliedImageData(maskImageRect)); CanvasPixelArray* srcPixelArray(imageData->data()); @@ -212,10 +220,6 @@ void RenderSVGResourceMasker::calculateMaskContentRepaintRect() FloatRect RenderSVGResourceMasker::resourceBoundingBox(RenderObject* object) { - // Save the reference to the calling object for relayouting it on changing resource properties. - if (!m_masker.contains(object)) - m_masker.set(object, new MaskerData); - // Resource was not layouted yet. Give back clipping rect of the mask. SVGMaskElement* maskElement = static_cast<SVGMaskElement*>(node()); FloatRect objectBoundingBox = object->objectBoundingBox(); diff --git a/WebCore/rendering/RenderSVGResourceMasker.h b/WebCore/rendering/RenderSVGResourceMasker.h index f6301cb..56f657b 100644 --- a/WebCore/rendering/RenderSVGResourceMasker.h +++ b/WebCore/rendering/RenderSVGResourceMasker.h @@ -69,6 +69,8 @@ private: void createMaskImage(MaskerData*, const SVGMaskElement*, RenderObject*); void calculateMaskContentRepaintRect(); + virtual bool childElementReferencesResource(const SVGRenderStyle*, const String&) const; + FloatRect m_maskBoundaries; HashMap<RenderObject*, MaskerData*> m_masker; }; diff --git a/WebCore/rendering/RenderSVGResourcePattern.cpp b/WebCore/rendering/RenderSVGResourcePattern.cpp index ba24fcf..a2234c8 100644 --- a/WebCore/rendering/RenderSVGResourcePattern.cpp +++ b/WebCore/rendering/RenderSVGResourcePattern.cpp @@ -48,7 +48,7 @@ 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); + markForLayoutAndResourceInvalidation(it->first, false); deleteAllValues(m_pattern); m_pattern.clear(); @@ -57,16 +57,26 @@ void RenderSVGResourcePattern::invalidateClients() 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); + markForLayoutAndResourceInvalidation(object, false); +} + +bool RenderSVGResourcePattern::childElementReferencesResource(const SVGRenderStyle* style, const String& referenceId) const +{ + if (style->hasFill()) { + if (style->fillPaint()->matchesTargetURI(referenceId)) + return true; + } + + if (style->hasStroke()) { + if (style->strokePaint()->matchesTargetURI(referenceId)) + return true; + } + + return false; } bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode) @@ -91,7 +101,6 @@ bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* PatternData* patternData = m_pattern.get(object); if (!patternData->pattern) { - // Create tile image OwnPtr<ImageBuffer> tileImage = createTileImage(patternData, patternElement, object); if (!tileImage) @@ -235,6 +244,10 @@ PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(PatternData* p if (!attributes.patternContentElement()) return 0; + // Early exit, if this resource contains a child which references ourselves. + if (containsCyclicReference(attributes.patternContentElement())) + return 0; + FloatRect objectBoundingBox = object->objectBoundingBox(); FloatRect patternBoundaries = calculatePatternBoundaries(attributes, objectBoundingBox, patternElement); AffineTransform patternTransform = attributes.patternTransform(); diff --git a/WebCore/rendering/RenderSVGResourcePattern.h b/WebCore/rendering/RenderSVGResourcePattern.h index 690b0de..ec89777 100644 --- a/WebCore/rendering/RenderSVGResourcePattern.h +++ b/WebCore/rendering/RenderSVGResourcePattern.h @@ -67,6 +67,8 @@ private: FloatRect calculatePatternBoundariesIncludingOverflow(PatternAttributes&, const FloatRect& objectBoundingBox, const AffineTransform& viewBoxCTM, const FloatRect& patternBoundaries) const; + virtual bool childElementReferencesResource(const SVGRenderStyle*, const String&) const; + HashMap<RenderObject*, PatternData*> m_pattern; }; diff --git a/WebCore/rendering/RenderSVGRoot.cpp b/WebCore/rendering/RenderSVGRoot.cpp index 396df19..1659e40 100644 --- a/WebCore/rendering/RenderSVGRoot.cpp +++ b/WebCore/rendering/RenderSVGRoot.cpp @@ -112,7 +112,7 @@ void RenderSVGRoot::layout() view()->disableLayoutState(); bool needsLayout = selfNeedsLayout(); - LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && needsLayout); + LayoutRepainter repainter(*this, needsLayout && m_everHadLayout && checkForRepaintDuringLayout()); IntSize oldSize(width(), height()); calcWidth(); diff --git a/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp b/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp index 9d3d26f..888dd57 100644 --- a/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp +++ b/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp @@ -96,6 +96,11 @@ void RenderSVGShadowTreeRootContainer::styleDidChange(StyleDifference diff, cons shadowRootRenderer->setStyle(style()); } +Node* RenderSVGShadowTreeRootContainer::rootElement() const +{ + return m_shadowRoot.get(); +} + } #endif diff --git a/WebCore/rendering/RenderSVGShadowTreeRootContainer.h b/WebCore/rendering/RenderSVGShadowTreeRootContainer.h index 81ae44b..bff2a87 100644 --- a/WebCore/rendering/RenderSVGShadowTreeRootContainer.h +++ b/WebCore/rendering/RenderSVGShadowTreeRootContainer.h @@ -39,6 +39,8 @@ public: void updateStyle(Node::StyleChange); virtual void updateFromElement(); + Node* rootElement() const; + private: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); diff --git a/WebCore/rendering/RenderSVGText.cpp b/WebCore/rendering/RenderSVGText.cpp index 12f3cb5..58348db 100644 --- a/WebCore/rendering/RenderSVGText.cpp +++ b/WebCore/rendering/RenderSVGText.cpp @@ -73,7 +73,7 @@ void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer, void RenderSVGText::layout() { ASSERT(needsLayout()); - LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); if (m_needsTransformUpdate) { SVGTextElement* text = static_cast<SVGTextElement*>(node()); @@ -98,6 +98,10 @@ void RenderSVGText::layout() ASSERT(childrenInline()); forceLayoutInlineChildren(); + // Invalidate all resources of this client, if we changed something. + if (m_everHadLayout && selfNeedsLayout()) + RenderSVGResource::invalidateAllResourcesOfRenderer(this); + repainter.repaintAfterLayout(); setNeedsLayout(false); } diff --git a/WebCore/rendering/RenderTextControlSingleLine.cpp b/WebCore/rendering/RenderTextControlSingleLine.cpp index b6c2916..71d5a86 100644 --- a/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -69,6 +69,8 @@ RenderTextControlSingleLine::~RenderTextControlSingleLine() if (m_innerBlock) m_innerBlock->detach(); + if (m_innerSpinButton) + m_innerSpinButton->detach(); if (m_outerSpinButton) m_outerSpinButton->detach(); } @@ -261,6 +263,12 @@ void RenderTextControlSingleLine::layout() if (currentHeight < height()) childBlock->setY((height() - currentHeight) / 2); + // Ignores the paddings for the inner spin button. + if (RenderBox* spinBox = m_innerSpinButton ? m_innerSpinButton->renderBox() : 0) { + spinBox->setLocation(spinBox->x() + paddingRight(), borderTop()); + spinBox->setHeight(height() - borderTop() - borderBottom()); + } + // 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) { @@ -292,6 +300,8 @@ bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, Hit hitInnerTextElement(result, xPos, yPos, tx, ty); // If we found a spin button, we're done. + if (m_innerSpinButton && result.innerNode() == m_innerSpinButton) + return true; if (m_outerSpinButton && result.innerNode() == m_outerSpinButton) return true; // If we're not a search field, or we already found the speech, results or cancel buttons, we're done. @@ -376,6 +386,8 @@ void RenderTextControlSingleLine::forwardEvent(Event* event) m_resultsButton->defaultEventHandler(event); else if (m_cancelButton && localPoint.x() > textRight) m_cancelButton->defaultEventHandler(event); + else if (m_innerSpinButton && localPoint.x() > textRight && localPoint.x() < textRight + m_innerSpinButton->renderBox()->width()) + m_innerSpinButton->defaultEventHandler(event); else if (m_outerSpinButton && localPoint.x() > textRight) m_outerSpinButton->defaultEventHandler(event); else @@ -469,6 +481,11 @@ int RenderTextControlSingleLine::textBlockWidth() const width -= cancelRenderer->width() + cancelRenderer->marginLeft() + cancelRenderer->marginRight(); } + if (RenderBox* spinRenderer = m_innerSpinButton ? m_innerSpinButton->renderBox() : 0) { + spinRenderer->calcWidth(); + width -= spinRenderer->width() + spinRenderer->marginLeft() + spinRenderer->marginRight(); + } + #if ENABLE(INPUT_SPEECH) if (RenderBox* speechRenderer = m_speechButton ? m_speechButton->renderBox() : 0) { speechRenderer->calcWidth(); @@ -534,6 +551,9 @@ int RenderTextControlSingleLine::preferredContentWidth(float charWidth) const result += cancelRenderer->borderLeft() + cancelRenderer->borderRight() + cancelRenderer->paddingLeft() + cancelRenderer->paddingRight(); + if (RenderBox* spinRenderer = m_innerSpinButton ? m_innerSpinButton->renderBox() : 0) + result += spinRenderer->minPrefWidth(); + #if ENABLE(INPUT_SPEECH) if (RenderBox* speechRenderer = m_speechButton ? m_speechButton->renderBox() : 0) { result += speechRenderer->borderLeft() + speechRenderer->borderRight() + @@ -598,7 +618,12 @@ void RenderTextControlSingleLine::createSubtreeIfNeeded() #endif if (!createSubtree) { RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get()); - if (inputElement()->hasSpinButton() && !m_outerSpinButton) { + bool hasSpinButton = inputElement()->hasSpinButton(); + if (hasSpinButton && !m_innerSpinButton) { + m_innerSpinButton = SpinButtonElement::create(node()); + m_innerSpinButton->attachInnerElement(node(), createInnerSpinButtonStyle(), renderArena()); + } + if (hasSpinButton && !m_outerSpinButton) { m_outerSpinButton = SpinButtonElement::create(node()); m_outerSpinButton->attachInnerElement(node(), createOuterSpinButtonStyle(), renderArena()); } @@ -767,6 +792,16 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createCancelButtonStyle(con return cancelBlockStyle.release(); } +PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerSpinButtonStyle() const +{ + ASSERT(node()->isHTMLElement()); + RefPtr<RenderStyle> buttonStyle = getCachedPseudoStyle(INNER_SPIN_BUTTON); + if (!buttonStyle) + buttonStyle = RenderStyle::create(); + buttonStyle->inheritFrom(style()); + return buttonStyle.release(); +} + PassRefPtr<RenderStyle> RenderTextControlSingleLine::createOuterSpinButtonStyle() const { ASSERT(node()->isHTMLElement()); @@ -880,6 +915,11 @@ String RenderTextControlSingleLine::itemText(unsigned listIndex) const return m_recentSearches[listIndex - 1]; } +String RenderTextControlSingleLine::itemLabel(unsigned) const +{ + return String(); +} + bool RenderTextControlSingleLine::itemIsEnabled(unsigned listIndex) const { if (!listIndex || itemIsSeparator(listIndex)) diff --git a/WebCore/rendering/RenderTextControlSingleLine.h b/WebCore/rendering/RenderTextControlSingleLine.h index ab9f711..92ecadd 100644 --- a/WebCore/rendering/RenderTextControlSingleLine.h +++ b/WebCore/rendering/RenderTextControlSingleLine.h @@ -98,6 +98,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> createInnerSpinButtonStyle() const; PassRefPtr<RenderStyle> createOuterSpinButtonStyle() const; #if ENABLE(INPUT_SPEECH) PassRefPtr<RenderStyle> createSpeechButtonStyle(const RenderStyle* startStyle) const; @@ -115,6 +116,7 @@ private: virtual void selectionChanged(unsigned, bool) {} virtual void selectionCleared() {} virtual String itemText(unsigned listIndex) const; + virtual String itemLabel(unsigned listIndex) const; virtual String itemToolTip(unsigned) const { return String(); } virtual String itemAccessibilityText(unsigned) const { return String(); } virtual bool itemIsEnabled(unsigned listIndex) const; @@ -145,6 +147,7 @@ private: RefPtr<TextControlInnerElement> m_innerBlock; RefPtr<SearchFieldResultsButtonElement> m_resultsButton; RefPtr<SearchFieldCancelButtonElement> m_cancelButton; + RefPtr<TextControlInnerElement> m_innerSpinButton; RefPtr<TextControlInnerElement> m_outerSpinButton; #if ENABLE(INPUT_SPEECH) RefPtr<InputFieldSpeechButtonElement> m_speechButton; diff --git a/WebCore/rendering/RenderTheme.cpp b/WebCore/rendering/RenderTheme.cpp index 2147b36..3fcb2c9 100644 --- a/WebCore/rendering/RenderTheme.cpp +++ b/WebCore/rendering/RenderTheme.cpp @@ -832,7 +832,7 @@ bool RenderTheme::isSpinUpButtonPartPressed(const RenderObject* o) const || !static_cast<Element*>(node)->isSpinButtonElement()) return false; SpinButtonElement* element = static_cast<SpinButtonElement*>(node); - return element->onUpButton(); + return element->upDownState() == SpinButtonElement::Up; } bool RenderTheme::isReadOnlyControl(const RenderObject* o) const @@ -845,19 +845,22 @@ bool RenderTheme::isReadOnlyControl(const RenderObject* o) const bool RenderTheme::isHovered(const RenderObject* o) const { - if (!o->node()) + Node* node = o->node(); + if (!node) return false; - return o->node()->hovered(); + if (!node->isElementNode() || !static_cast<Element*>(node)->isSpinButtonElement()) + return node->hovered(); + SpinButtonElement* element = static_cast<SpinButtonElement*>(node); + return element->hovered() && element->upDownState() != SpinButtonElement::Indeterminate; } bool RenderTheme::isSpinUpButtonPartHovered(const RenderObject* o) const { Node* node = o->node(); - if (!node || !node->active() || !node->isElementNode() - || !static_cast<Element*>(node)->isSpinButtonElement()) + if (!node || !node->isElementNode() || !static_cast<Element*>(node)->isSpinButtonElement()) return false; SpinButtonElement* element = static_cast<SpinButtonElement*>(node); - return element->onUpButton(); + return element->upDownState() == SpinButtonElement::Up; } bool RenderTheme::isDefault(const RenderObject* o) const diff --git a/WebCore/rendering/RenderThemeChromiumLinux.cpp b/WebCore/rendering/RenderThemeChromiumLinux.cpp index c29353d..de83ae9 100644 --- a/WebCore/rendering/RenderThemeChromiumLinux.cpp +++ b/WebCore/rendering/RenderThemeChromiumLinux.cpp @@ -27,14 +27,13 @@ #include "CSSValueKeywords.h" #include "Color.h" +#include "PlatformThemeChromiumGtk.h" #include "RenderObject.h" +#include "ScrollbarTheme.h" #include "UserAgentStyleSheets.h" namespace WebCore { -unsigned RenderThemeChromiumLinux::m_thumbInactiveColor = 0xeaeaea; -unsigned RenderThemeChromiumLinux::m_thumbActiveColor = 0xf4f4f4; -unsigned RenderThemeChromiumLinux::m_trackColor = 0xd3d3d3; unsigned RenderThemeChromiumLinux::m_activeSelectionBackgroundColor = 0xff1e90ff; unsigned RenderThemeChromiumLinux::m_activeSelectionForegroundColor = @@ -168,12 +167,29 @@ void RenderThemeChromiumLinux::setSelectionColors( m_inactiveSelectionForegroundColor = inactiveForegroundColor; } -void RenderThemeChromiumLinux::setScrollbarColors( - SkColor inactiveColor, SkColor activeColor, SkColor trackColor) +void RenderThemeChromiumLinux::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { - m_thumbInactiveColor = inactiveColor; - m_thumbActiveColor = activeColor; - m_trackColor = trackColor; + int width = ScrollbarTheme::nativeTheme()->scrollbarThickness(); + style->setWidth(Length(width, Fixed)); + style->setMinWidth(Length(width, Fixed)); +} + +bool RenderThemeChromiumLinux::paintInnerSpinButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) +{ + ControlStates northStates = controlStatesForRenderer(object); + ControlStates southStates = northStates; + if (northStates & SpinUpState) + southStates &= ~(HoverState | PressedState); + else + northStates &= ~(HoverState | PressedState); + + IntRect half = rect; + half.setHeight(rect.height() / 2); + PlatformThemeChromiumGtk::paintArrowButton(info.context, half, PlatformThemeChromiumGtk::North, northStates); + + half.setY(rect.y() + rect.height() / 2); + PlatformThemeChromiumGtk::paintArrowButton(info.context, half, PlatformThemeChromiumGtk::South, southStates); + return false; } } // namespace WebCore diff --git a/WebCore/rendering/RenderThemeChromiumLinux.h b/WebCore/rendering/RenderThemeChromiumLinux.h index c60dec3..9eeca97 100644 --- a/WebCore/rendering/RenderThemeChromiumLinux.h +++ b/WebCore/rendering/RenderThemeChromiumLinux.h @@ -59,18 +59,14 @@ namespace WebCore { static void setCaretBlinkInterval(double interval); virtual double caretBlinkIntervalInternal() const; + virtual void adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&); + static void setSelectionColors(unsigned activeBackgroundColor, unsigned activeForegroundColor, unsigned inactiveBackgroundColor, unsigned inactiveForegroundColor); - static void setScrollbarColors(unsigned inactive_color, - unsigned active_color, - unsigned track_color); - static unsigned thumbInactiveColor() { return m_thumbInactiveColor; } - static unsigned thumbActiveColor() { return m_thumbActiveColor; } - static unsigned trackColor() { return m_trackColor; } - private: RenderThemeChromiumLinux(); virtual ~RenderThemeChromiumLinux(); @@ -84,10 +80,6 @@ namespace WebCore { static unsigned m_activeSelectionForegroundColor; static unsigned m_inactiveSelectionBackgroundColor; static unsigned m_inactiveSelectionForegroundColor; - - static unsigned m_thumbInactiveColor; - static unsigned m_thumbActiveColor; - static unsigned m_trackColor; }; } // namespace WebCore diff --git a/WebCore/rendering/RenderThemeChromiumWin.cpp b/WebCore/rendering/RenderThemeChromiumWin.cpp index 1172f96..3023798 100644 --- a/WebCore/rendering/RenderThemeChromiumWin.cpp +++ b/WebCore/rendering/RenderThemeChromiumWin.cpp @@ -29,8 +29,8 @@ #include <uxtheme.h> #include <vssym32.h> -#include "ChromiumBridge.h" #include "CSSValueKeywords.h" +#include "ChromiumBridge.h" #include "CurrentTime.h" #include "FontSelector.h" #include "FontUtilsChromiumWin.h" @@ -57,53 +57,71 @@ namespace WebCore { namespace { -class ThemePainter : public TransparencyWin { +class ThemePainter { public: ThemePainter(GraphicsContext* context, const IntRect& r) { - TransformMode transformMode = getTransformMode(context->getCTM()); - init(context, getLayerMode(context, transformMode), transformMode, r); + TransparencyWin::TransformMode transformMode = getTransformMode(context->getCTM()); + m_helper.init(context, getLayerMode(context, transformMode), transformMode, r); + + if (!m_helper.context()) { + // TransparencyWin doesn't have well-defined copy-ctor nor op=() + // so we re-initialize it instead of assigning a fresh istance. + // On the reinitialization, we fallback to use NoLayer mode. + // Note that the original initialization failure can be caused by + // a failure of an internal buffer allocation and NoLayer mode + // does not have such buffer allocations. + m_helper.~TransparencyWin(); + new (&m_helper) TransparencyWin(); + m_helper.init(context, TransparencyWin::NoLayer, transformMode, r); + } } ~ThemePainter() { - composite(); + m_helper.composite(); } + GraphicsContext* context() { return m_helper.context(); } + const IntRect& drawRect() { return m_helper.drawRect(); } + private: + static bool canvasHasMultipleLayers(const SkCanvas* canvas) { SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false); - iter.next(); // There is always at least one layer. - return !iter.done(); // There is > 1 layer if the the iterator can stil advance. + iter.next(); // There is always at least one layer. + return !iter.done(); // There is > 1 layer if the the iterator can stil advance. } - static LayerMode getLayerMode(GraphicsContext* context, TransformMode transformMode) + static TransparencyWin::LayerMode getLayerMode(GraphicsContext* context, TransparencyWin::TransformMode transformMode) { - if (context->platformContext()->isDrawingToImageBuffer()) // Might have transparent background. - return WhiteLayer; - else if (canvasHasMultipleLayers(context->platformContext()->canvas())) // Needs antialiasing help. - return OpaqueCompositeLayer; - else // Nothing interesting. - return transformMode == KeepTransform ? NoLayer : OpaqueCompositeLayer; + if (context->platformContext()->isDrawingToImageBuffer()) // Might have transparent background. + return TransparencyWin::WhiteLayer; + if (canvasHasMultipleLayers(context->platformContext()->canvas())) // Needs antialiasing help. + return TransparencyWin::OpaqueCompositeLayer; + // Nothing interesting. + return transformMode == TransparencyWin::KeepTransform ? TransparencyWin::NoLayer : TransparencyWin::OpaqueCompositeLayer; } - static TransformMode getTransformMode(const AffineTransform& matrix) + static TransparencyWin::TransformMode getTransformMode(const AffineTransform& matrix) { - if (matrix.b() != 0 || matrix.c() != 0) // Skew. - return Untransform; - else if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale. - return ScaleTransform; - else // Nothing interesting. - return KeepTransform; + if (matrix.b() || matrix.c()) // Skew. + return TransparencyWin::Untransform; + if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale. + return TransparencyWin::ScaleTransform; + // Nothing interesting. + return TransparencyWin::KeepTransform; } + + TransparencyWin m_helper; }; -} // namespace +} // namespace static void getNonClientMetrics(NONCLIENTMETRICS* metrics) { - static UINT size = WebCore::isVistaOrNewer() ? + static UINT size = isVistaOrNewer() ? sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; metrics->cbSize = size; bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0); @@ -139,7 +157,7 @@ static float systemFontSize(const LOGFONT& font) if (size < 0) { HFONT hFont = CreateFontIndirect(&font); if (hFont) { - HDC hdc = GetDC(0); // What about printing? Is this the right DC? + HDC hdc = GetDC(0); // What about printing? Is this the right DC? if (hdc) { HGDIOBJ hObject = SelectObject(hdc, hFont); TEXTMETRIC tm; @@ -170,8 +188,8 @@ static float pointsToPixels(float points) { static float pixelsPerInch = 0.0f; if (!pixelsPerInch) { - HDC hdc = GetDC(0); // What about printing? Is this the right DC? - if (hdc) { // Can this ever actually be NULL? + HDC hdc = GetDC(0); // What about printing? Is this the right DC? + if (hdc) { // Can this ever actually be NULL? pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY); ReleaseDC(0, hdc); } else { @@ -186,7 +204,7 @@ static float pointsToPixels(float points) static double querySystemBlinkInterval(double defaultInterval) { UINT blinkTime = GetCaretBlinkTime(); - if (blinkTime == 0) + if (!blinkTime) return defaultInterval; if (blinkTime == INFINITE) return 0; @@ -216,7 +234,7 @@ bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const { if (ChromiumBridge::layoutTestMode()) - return Color(0x00, 0x00, 0xff); // Royal blue. + return Color(0x00, 0x00, 0xff); // Royal blue. COLORREF color = GetSysColor(COLOR_HIGHLIGHT); return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); } @@ -224,7 +242,7 @@ Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const { if (ChromiumBridge::layoutTestMode()) - return Color(0x99, 0x99, 0x99); // Medium gray. + return Color(0x99, 0x99, 0x99); // Medium gray. COLORREF color = GetSysColor(COLOR_GRAYTEXT); return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); } @@ -232,7 +250,7 @@ Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const Color RenderThemeChromiumWin::platformActiveSelectionForegroundColor() const { if (ChromiumBridge::layoutTestMode()) - return Color(0xff, 0xff, 0xcc); // Pale yellow. + return Color(0xff, 0xff, 0xcc); // Pale yellow. COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT); return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); } @@ -244,7 +262,7 @@ Color RenderThemeChromiumWin::platformInactiveSelectionForegroundColor() const Color RenderThemeChromiumWin::platformActiveTextSearchHighlightColor() const { - return Color(0xff, 0x96, 0x32); // Orange. + return Color(0xff, 0x96, 0x32); // Orange. } Color RenderThemeChromiumWin::platformInactiveTextSearchHighlightColor() const @@ -387,7 +405,7 @@ bool RenderThemeChromiumWin::paintButton(RenderObject* o, const PaintInfo& i, co { const ThemeData& themeData = getThemeData(o); - WebCore::ThemePainter painter(i.context, r); + ThemePainter painter(i.context, r); ChromiumBridge::paintButton(painter.context(), themeData.m_part, themeData.m_state, @@ -405,7 +423,7 @@ bool RenderThemeChromiumWin::paintSliderTrack(RenderObject* o, const PaintInfo& { const ThemeData& themeData = getThemeData(o); - WebCore::ThemePainter painter(i.context, r); + ThemePainter painter(i.context, r); ChromiumBridge::paintTrackbar(painter.context(), themeData.m_part, themeData.m_state, @@ -436,7 +454,7 @@ bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const PaintInfo& i, // draw individual borders and then pass that to skia so we can avoid // drawing any borders that are set to 0. For non-zero borders, we draw the // border, but webkit just draws over it. - bool drawEdges = !(borderRight == 0 && borderLeft == 0 && borderTop == 0 && borderBottom == 0); + bool drawEdges = !(!borderRight && !borderLeft && !borderTop && !borderBottom); paintTextFieldInternal(o, i, r, drawEdges); @@ -462,7 +480,7 @@ bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const PaintInfo& i, r.height() - (spacingTop + spacingBottom)); // Get the correct theme data for a textfield and paint the menu. - WebCore::ThemePainter painter(i.context, rect); + ThemePainter painter(i.context, rect); ChromiumBridge::paintMenuList(painter.context(), CP_DROPDOWNBUTTON, determineState(o), @@ -487,19 +505,20 @@ double RenderThemeChromiumWin::caretBlinkIntervalInternal() const return blinkInterval; } -unsigned RenderThemeChromiumWin::determineState(RenderObject* o) +unsigned RenderThemeChromiumWin::determineState(RenderObject* o, ControlSubPart subPart) { unsigned result = TS_NORMAL; ControlPart appearance = o->style()->appearance(); if (!isEnabled(o)) result = TS_DISABLED; - else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance || SearchFieldPart == appearance)) - result = ETS_READONLY; // Readonly is supported on textfields. - else if (isPressed(o)) // Active overrides hover and focused. + else if (isReadOnlyControl(o)) + result = (appearance == TextFieldPart || appearance == TextAreaPart || appearance == SearchFieldPart) ? ETS_READONLY : TS_DISABLED; + // Active overrides hover and focused. + else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o)) result = TS_PRESSED; else if (supportsFocus(appearance) && isFocused(o)) result = ETS_FOCUSED; - else if (isHovered(o)) + else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o)) result = TS_HOT; // CBS_UNCHECKED*: 1-4 @@ -526,7 +545,7 @@ unsigned RenderThemeChromiumWin::determineSliderThumbState(RenderObject* o) return result; } -unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o) +unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o, ControlSubPart subPart) { unsigned result = 0; @@ -548,13 +567,14 @@ unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o) else if (isHovered(o)) result = DFCS_HOT; } else { - if (!isEnabled(o)) + if (!isEnabled(o) || isReadOnlyControl(o)) result = DFCS_INACTIVE; - else if (isPressed(o)) // Active supersedes hover + // Active supersedes hover + else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o)) result = DFCS_PUSHED; else if (supportsFocus(part) && isFocused(o)) // So does focused result = 0; - else if (isHovered(o)) + else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o)) result = DFCS_HOT; // Classic theme can't represent indeterminate states. Use unchecked appearance. if (isChecked(o) && !isIndeterminate(o)) @@ -563,7 +583,7 @@ unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o) return result; } -ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o) +ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o, ControlSubPart subPart) { ThemeData result; switch (o->style()->appearance()) { @@ -608,9 +628,14 @@ ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o) result.m_part = EP_EDITTEXT; result.m_state = determineState(o); break; + case InnerSpinButtonPart: + result.m_part = subPart == SpinButtonUp ? SPNP_UP : SPNP_DOWN; + result.m_state = determineState(o, subPart); + result.m_classicState = subPart == SpinButtonUp ? DFCS_SCROLLUP : DFCS_SCROLLDOWN; + break; } - result.m_classicState |= determineClassicState(o); + result.m_classicState |= determineClassicState(o, subPart); return result; } @@ -646,7 +671,7 @@ bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o, } { const ThemeData& themeData = getThemeData(o); - WebCore::ThemePainter painter(i.context, r); + ThemePainter painter(i.context, r); ChromiumBridge::paintTextField(painter.context(), themeData.m_part, themeData.m_state, @@ -662,6 +687,37 @@ bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o, return false; } +void RenderThemeChromiumWin::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + int width = ScrollbarTheme::nativeTheme()->scrollbarThickness(); + style->setWidth(Length(width, Fixed)); + style->setMinWidth(Length(width, Fixed)); +} + +bool RenderThemeChromiumWin::paintInnerSpinButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) +{ + IntRect half = rect; + + half.setHeight(rect.height() / 2); + const ThemeData& upThemeData = getThemeData(object, SpinButtonUp); + ThemePainter upPainter(info.context, half); + ChromiumBridge::paintSpinButton(upPainter.context(), + upThemeData.m_part, + upThemeData.m_state, + upThemeData.m_classicState, + upPainter.drawRect()); + + half.setY(rect.y() + rect.height() / 2); + const ThemeData& downThemeData = getThemeData(object, SpinButtonDown); + ThemePainter downPainter(info.context, half); + ChromiumBridge::paintSpinButton(downPainter.context(), + downThemeData.m_part, + downThemeData.m_state, + downThemeData.m_classicState, + downPainter.drawRect()); + return false; +} + #if ENABLE(PROGRESS_TAG) // MSDN says that update intervals for the bar is 30ms. diff --git a/WebCore/rendering/RenderThemeChromiumWin.h b/WebCore/rendering/RenderThemeChromiumWin.h index c6c95e6..661b623 100644 --- a/WebCore/rendering/RenderThemeChromiumWin.h +++ b/WebCore/rendering/RenderThemeChromiumWin.h @@ -86,6 +86,8 @@ namespace WebCore { // See comment in RenderThemeChromiumSkia::setDefaultFontSize() regarding ugliness of this hack. static void setDefaultFontSize(int); + virtual void adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&); #if ENABLE(PROGRESS_TAG) virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const; @@ -98,14 +100,20 @@ namespace WebCore { virtual double caretBlinkIntervalInternal() const; private: + enum ControlSubPart { + None, + SpinButtonDown, + SpinButtonUp, + }; + RenderThemeChromiumWin() { } virtual ~RenderThemeChromiumWin() { } - unsigned determineState(RenderObject*); + unsigned determineState(RenderObject*, ControlSubPart = None); unsigned determineSliderThumbState(RenderObject*); - unsigned determineClassicState(RenderObject*); + unsigned determineClassicState(RenderObject*, ControlSubPart = None); - ThemeData getThemeData(RenderObject*); + ThemeData getThemeData(RenderObject*, ControlSubPart = None); bool paintTextFieldInternal(RenderObject*, const PaintInfo&, const IntRect&, bool); }; diff --git a/WebCore/rendering/RenderThemeMac.mm b/WebCore/rendering/RenderThemeMac.mm index bbf6906..cc2ff1f 100644 --- a/WebCore/rendering/RenderThemeMac.mm +++ b/WebCore/rendering/RenderThemeMac.mm @@ -826,6 +826,8 @@ bool RenderThemeMac::paintMeter(RenderObject* renderObject, const PaintInfo& pai if (!renderObject->isMeter()) return true; + LocalCurrentGraphicsContext localContext(paintInfo.context); + // Becaue NSLevelIndicatorCell doesn't support vertical gauge, we use a portable version if (rect.width() < rect.height()) return RenderTheme::paintMeter(renderObject, paintInfo, rect); @@ -1379,8 +1381,8 @@ bool RenderThemeMac::paintSliderThumb(RenderObject* o, const PaintInfo& paintInf bool RenderThemeMac::paintSearchField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { - NSSearchFieldCell* search = this->search(); LocalCurrentGraphicsContext localContext(paintInfo.context); + NSSearchFieldCell* search = this->search(); setSearchCellState(o, r); @@ -1480,6 +1482,7 @@ bool RenderThemeMac::paintSearchFieldCancelButton(RenderObject* o, const PaintIn if (!input->renderer()->isBox()) return false; + LocalCurrentGraphicsContext localContext(paintInfo.context); setSearchCellState(input->renderer(), r); NSSearchFieldCell* search = this->search(); @@ -1562,12 +1565,13 @@ void RenderThemeMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, style->setBoxShadow(0); } -bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo&, const IntRect& r) +bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { Node* input = o->node()->shadowAncestorNode(); if (!input->renderer()->isBox()) return false; + LocalCurrentGraphicsContext localContext(paintInfo.context); setSearchCellState(input->renderer(), r); NSSearchFieldCell* search = this->search(); @@ -1600,6 +1604,7 @@ bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const PaintI if (!input->renderer()->isBox()) return false; + LocalCurrentGraphicsContext localContext(paintInfo.context); setSearchCellState(input->renderer(), r); NSSearchFieldCell* search = this->search(); diff --git a/WebCore/rendering/RenderTreeAsText.cpp b/WebCore/rendering/RenderTreeAsText.cpp index 26f40ab..408015c 100644 --- a/WebCore/rendering/RenderTreeAsText.cpp +++ b/WebCore/rendering/RenderTreeAsText.cpp @@ -234,9 +234,9 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, ts << " " << r; if (!(o.isText() && !o.isBR())) { - if (o.isFileUploadControl()) { + if (o.isFileUploadControl()) ts << " " << quoteAndEscapeNonPrintables(toRenderFileUploadControl(&o)->fileTextValue()); - } + if (o.parent() && (o.parent()->style()->color() != o.style()->color())) ts << " [color=" << o.style()->color().name() << "]"; @@ -355,6 +355,24 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, ts << ": " << text; } } + + if (behavior & RenderAsTextShowIDAndClass) { + if (Node* node = o.node()) { + if (node->hasID()) + ts << " id=\"" + static_cast<Element*>(node)->getIdAttribute() + "\""; + + if (node->hasClass()) { + StyledElement* styledElement = static_cast<StyledElement*>(node); + String classes; + for (size_t i = 0; i < styledElement->classNames().size(); ++i) { + if (i > 0) + classes += " "; + classes += styledElement->classNames()[i]; + } + ts << " class=\"" + classes + "\""; + } + } + } #if PLATFORM(QT) // Print attributes of embedded QWidgets. E.g. when the WebCore::Widget @@ -580,6 +598,7 @@ static String nodePosition(Node* node) { String result; + Element* body = node->document()->body(); Node* parent; for (Node* n = node; n; n = parent) { parent = n->parentNode(); @@ -587,9 +606,14 @@ static String nodePosition(Node* node) parent = n->shadowParentNode(); if (n != node) result += " of "; - if (parent) + if (parent) { + if (body && n == body) { + // We don't care what offset body may be in the document. + result += "body"; + break; + } result += "child " + String::number(n->nodeIndex()) + " {" + getTagName(n) + "}"; - else + } else result += "document"; } diff --git a/WebCore/rendering/RenderTreeAsText.h b/WebCore/rendering/RenderTreeAsText.h index 1635e79..645ccc0 100644 --- a/WebCore/rendering/RenderTreeAsText.h +++ b/WebCore/rendering/RenderTreeAsText.h @@ -40,7 +40,8 @@ enum RenderAsTextBehaviorFlags { RenderAsTextShowLayerNesting = 1 << 1, // Annotate the layer lists. RenderAsTextShowCompositedLayers = 1 << 2, // Show which layers are composited. RenderAsTextShowAddresses = 1 << 3, // Show layer and renderer addresses. - RenderAsTextPrintingMode = 1 << 4 // Dump the tree in printing mode. + RenderAsTextShowIDAndClass = 1 << 4, // Show id and class attributes + RenderAsTextPrintingMode = 1 << 5 // Dump the tree in printing mode. }; typedef unsigned RenderAsTextBehavior; diff --git a/WebCore/rendering/RenderView.cpp b/WebCore/rendering/RenderView.cpp index 232dd5d..449c15c 100644 --- a/WebCore/rendering/RenderView.cpp +++ b/WebCore/rendering/RenderView.cpp @@ -456,13 +456,15 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. oldSelectedObjects.set(os, new RenderSelectionInfo(os, true)); - RenderBlock* cb = os->containingBlock(); - while (cb && !cb->isRenderView()) { - RenderBlockSelectionInfo* blockInfo = oldSelectedBlocks.get(cb); - if (blockInfo) - break; - oldSelectedBlocks.set(cb, new RenderBlockSelectionInfo(cb)); - cb = cb->containingBlock(); + if (blockRepaintMode == RepaintNewXOROld) { + RenderBlock* cb = os->containingBlock(); + while (cb && !cb->isRenderView()) { + RenderBlockSelectionInfo* blockInfo = oldSelectedBlocks.get(cb); + if (blockInfo) + break; + oldSelectedBlocks.set(cb, new RenderBlockSelectionInfo(cb)); + cb = cb->containingBlock(); + } } } @@ -565,8 +567,7 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e RenderBlockSelectionInfo* newInfo = newSelectedBlocks.get(block); RenderBlockSelectionInfo* oldInfo = i->second; if (!newInfo || oldInfo->rects() != newInfo->rects() || oldInfo->state() != newInfo->state()) { - if (blockRepaintMode == RepaintNewXOROld) - oldInfo->repaint(); + oldInfo->repaint(); if (newInfo) { newInfo->repaint(); newSelectedBlocks.remove(block); diff --git a/WebCore/rendering/TextControlInnerElements.cpp b/WebCore/rendering/TextControlInnerElements.cpp index 36e30af..24e1d74 100644 --- a/WebCore/rendering/TextControlInnerElements.cpp +++ b/WebCore/rendering/TextControlInnerElements.cpp @@ -36,8 +36,10 @@ #include "HTMLNames.h" #include "HTMLTextAreaElement.h" #include "MouseEvent.h" +#include "Page.h" #include "RenderLayer.h" #include "RenderTextControlSingleLine.h" +#include "SpeechInput.h" namespace WebCore { @@ -246,7 +248,7 @@ void SearchFieldCancelButtonElement::defaultEventHandler(Event* event) inline SpinButtonElement::SpinButtonElement(Node* shadowParent) : TextControlInnerElement(shadowParent->document(), shadowParent) , m_capturing(false) - , m_onUpButton(false) + , m_upDownState(Indeterminate) { } @@ -278,12 +280,19 @@ void SpinButtonElement::defaultEventHandler(Event* event) } HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); + if (input->disabled() || input->isReadOnlyFormControl()) { + if (!event->defaultHandled()) + HTMLDivElement::defaultEventHandler(event); + return; + } + IntPoint local = roundedIntPoint(box->absoluteToLocal(mouseEvent->absoluteLocation(), false, true)); if (event->type() == eventNames().clickEvent) { if (box->borderBoxRect().contains(local)) { + RefPtr<Node> protector(input); input->focus(); input->select(); - if (local.y() < box->y() + box->height() / 2) + if (local.y() < box->height() / 2) input->stepUpFromRenderer(1); else input->stepUpFromRenderer(-1); @@ -297,9 +306,9 @@ void SpinButtonElement::defaultEventHandler(Event* event) m_capturing = true; } } - bool oldOnUpButton = m_onUpButton; - m_onUpButton = local.y() < box->y() + box->height() / 2; - if (m_onUpButton != oldOnUpButton) + UpDownState oldUpDownState = m_upDownState; + m_upDownState = local.y() < box->height() / 2 ? Up : Down; + if (m_upDownState != oldUpDownState) renderer()->repaint(); } else { if (m_capturing) { @@ -315,12 +324,21 @@ void SpinButtonElement::defaultEventHandler(Event* event) HTMLDivElement::defaultEventHandler(event); } +void SpinButtonElement::setHovered(bool flag) +{ + if (!hovered() && flag) + m_upDownState = Indeterminate; + TextControlInnerElement::setHovered(flag); +} + + // ---------------------------- #if ENABLE(INPUT_SPEECH) inline InputFieldSpeechButtonElement::InputFieldSpeechButtonElement(Document* document) : TextControlInnerElement(document) + , m_capturing(false) { } @@ -331,8 +349,73 @@ PassRefPtr<InputFieldSpeechButtonElement> InputFieldSpeechButtonElement::create( void InputFieldSpeechButtonElement::defaultEventHandler(Event* event) { - // FIXME: Start speech recognition here. - HTMLDivElement::defaultEventHandler(event); + // On mouse down, select the text and set focus. + HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); + if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { + if (renderer() && renderer()->visibleToHitTesting()) { + if (Frame* frame = document()->frame()) { + frame->eventHandler()->setCapturingMouseEventsNode(this); + m_capturing = true; + } + } + // The call to focus() below dispatches a focus event, and an event handler in the page might + // remove the input element from DOM. To make sure it remains valid until we finish our work + // here, we take a temporary reference. + RefPtr<HTMLInputElement> holdRef(input); + input->focus(); + input->select(); + event->setDefaultHandled(); + } + // On mouse up, start speech recognition. + if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { + if (m_capturing && renderer() && renderer()->visibleToHitTesting()) { + if (Frame* frame = document()->frame()) { + frame->eventHandler()->setCapturingMouseEventsNode(0); + m_capturing = false; + } + if (hovered()) { + speechInput()->startRecognition(); + event->setDefaultHandled(); + } + } + } + + if (!event->defaultHandled()) + HTMLDivElement::defaultEventHandler(event); +} + +SpeechInput* InputFieldSpeechButtonElement::speechInput() +{ + if (!m_speechInput) + m_speechInput.set(new SpeechInput(document()->page()->speechInputClient(), this)); + return m_speechInput.get(); +} + +void InputFieldSpeechButtonElement::recordingComplete() +{ + // FIXME: Add UI feedback here to indicate that audio recording stopped and recognition is + // in progress. +} + +void InputFieldSpeechButtonElement::setRecognitionResult(const String& result) +{ + HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); + // The call to setValue() below dispatches an event, and an event handler in the page might + // remove the input element from DOM. To make sure it remains valid until we finish our work + // here, we take a temporary reference. + RefPtr<HTMLInputElement> holdRef(input); + input->setValue(result); + input->dispatchFormControlChangeEvent(); + renderer()->repaint(); +} + +void InputFieldSpeechButtonElement::detach() +{ + if (m_capturing) { + if (Frame* frame = document()->frame()) + frame->eventHandler()->setCapturingMouseEventsNode(0); + } + TextControlInnerElement::detach(); } #endif // ENABLE(INPUT_SPEECH) diff --git a/WebCore/rendering/TextControlInnerElements.h b/WebCore/rendering/TextControlInnerElements.h index 1884a34..68d6ff4 100644 --- a/WebCore/rendering/TextControlInnerElements.h +++ b/WebCore/rendering/TextControlInnerElements.h @@ -28,9 +28,11 @@ #define TextControlInnerElements_h #include "HTMLDivElement.h" +#include "SpeechInputListener.h" namespace WebCore { +class SpeechInput; class String; class TextControlInnerElement : public HTMLDivElement { @@ -88,33 +90,50 @@ private: class SpinButtonElement : public TextControlInnerElement { public: - static PassRefPtr<SpinButtonElement> create(Node*); + enum UpDownState { + Indeterminate, // Hovered, but the event is not handled. + Down, + Up, + }; - // FIXME: "Spin button on up button" is not a phrase with a single clear meaning. - // Need a name for this that makes it clearer. - bool onUpButton() const { return m_onUpButton; } + static PassRefPtr<SpinButtonElement> create(Node*); + UpDownState upDownState() const { return m_upDownState; } private: SpinButtonElement(Node*); virtual bool isSpinButtonElement() const { return true; } - virtual bool isEnabledFormControl() { return static_cast<Element*>(shadowAncestorNode())->isEnabledFormControl(); } + // FIXME: shadowAncestorNode() should be const. + virtual bool isEnabledFormControl() const { return static_cast<Element*>(const_cast<SpinButtonElement*>(this)->shadowAncestorNode())->isEnabledFormControl(); } + virtual bool isReadOnlyFormControl() const { return static_cast<Element*>(const_cast<SpinButtonElement*>(this)->shadowAncestorNode())->isReadOnlyFormControl(); } virtual void defaultEventHandler(Event*); + virtual void setHovered(bool = true); bool m_capturing; - bool m_onUpButton; + UpDownState m_upDownState; }; #if ENABLE(INPUT_SPEECH) -class InputFieldSpeechButtonElement : public TextControlInnerElement { +class InputFieldSpeechButtonElement + : public TextControlInnerElement, + public SpeechInputListener { public: static PassRefPtr<InputFieldSpeechButtonElement> create(Document*); virtual void defaultEventHandler(Event*); + // SpeechInputListener methods. + void recordingComplete(); + void setRecognitionResult(const String& result); + private: InputFieldSpeechButtonElement(Document*); + virtual void detach(); + SpeechInput* speechInput(); + + bool m_capturing; + OwnPtr<SpeechInput> m_speechInput; }; #endif // ENABLE(INPUT_SPEECH) diff --git a/WebCore/rendering/style/FillLayer.cpp b/WebCore/rendering/style/FillLayer.cpp index 59f3bb2..3469e97 100644 --- a/WebCore/rendering/style/FillLayer.cpp +++ b/WebCore/rendering/style/FillLayer.cpp @@ -129,17 +129,6 @@ bool FillLayer::operator==(const FillLayer& o) const void FillLayer::fillUnsetProperties() { FillLayer* curr; - for (curr = this; curr && curr->isImageSet(); curr = curr->next()) { } - if (curr && curr != this) { - // We need to fill in the remaining values with the pattern specified. - for (FillLayer* pattern = this; curr; curr = curr->next()) { - curr->m_image = pattern->m_image; - pattern = pattern->next(); - if (pattern == curr || !pattern) - pattern = this; - } - } - for (curr = this; curr && curr->isXPositionSet(); curr = curr->next()) { } if (curr && curr != this) { // We need to fill in the remaining values with the pattern specified. @@ -243,15 +232,27 @@ void FillLayer::fillUnsetProperties() void FillLayer::cullEmptyLayers() { + // CSS3 background layering: the number of background layers is determined + // by the number of values in the 'background-image' property. + // http://www.w3.org/TR/css3-background/#layering + FillLayer* next; for (FillLayer* p = this; p; p = next) { next = p->m_next; - if (next && !next->isImageSet() && - !next->isXPositionSet() && !next->isYPositionSet() && - !next->isAttachmentSet() && !next->isClipSet() && - !next->isCompositeSet() && !next->isOriginSet() && - !next->isRepeatXSet() && !next->isRepeatYSet() - && !next->isSizeSet()) { + if (!next) + break; + + bool anyAttributeSet = next->isXPositionSet() + || next->isYPositionSet() + || next->isAttachmentSet() + || next->isClipSet() + || next->isCompositeSet() + || next->isOriginSet() + || next->isRepeatXSet() + || next->isRepeatYSet() + || next->isSizeSet(); + + if (!next->isImageSet() || !anyAttributeSet) { delete next; p->m_next = 0; break; diff --git a/WebCore/rendering/style/RenderStyle.h b/WebCore/rendering/style/RenderStyle.h index 782508e..58af7cf 100644 --- a/WebCore/rendering/style/RenderStyle.h +++ b/WebCore/rendering/style/RenderStyle.h @@ -876,8 +876,8 @@ public: void adjustBackgroundLayers() { if (backgroundLayers()->next()) { - accessBackgroundLayers()->cullEmptyLayers(); accessBackgroundLayers()->fillUnsetProperties(); + accessBackgroundLayers()->cullEmptyLayers(); } } @@ -887,8 +887,8 @@ public: void adjustMaskLayers() { if (maskLayers()->next()) { - accessMaskLayers()->cullEmptyLayers(); accessMaskLayers()->fillUnsetProperties(); + accessMaskLayers()->cullEmptyLayers(); } } |