diff options
Diffstat (limited to 'WebCore/rendering')
32 files changed, 1642 insertions, 409 deletions
diff --git a/WebCore/rendering/AutoTableLayout.cpp b/WebCore/rendering/AutoTableLayout.cpp index 1633d88..ea8b416 100644 --- a/WebCore/rendering/AutoTableLayout.cpp +++ b/WebCore/rendering/AutoTableLayout.cpp @@ -66,9 +66,9 @@ void AutoTableLayout::recalcColumn(int effCol) int numRows = section->numRows(); for (int i = 0; i < numRows; i++) { RenderTableSection::CellStruct current = section->cellAt(i, effCol); - RenderTableCell* cell = current.cell; + RenderTableCell* cell = current.primaryCell(); - bool cellHasContent = cell && (cell->firstChild() || cell->style()->hasBorder() || cell->style()->hasPadding()); + bool cellHasContent = cell && !current.inColSpan && (cell->firstChild() || cell->style()->hasBorder() || cell->style()->hasPadding()); if (cellHasContent) l.emptyCellsOnly = false; @@ -125,7 +125,7 @@ void AutoTableLayout::recalcColumn(int effCol) break; } } else { - if (cell && (!effCol || section->cellAt(i, effCol-1).cell != cell)) { + if (cell && (!effCol || section->primaryCellAt(i, effCol-1) != cell)) { // This spanning cell originates in this column. Ensure we have // a min/max width of at least 1px for this column now. l.minWidth = max(l.minWidth, cellHasContent ? 1 : 0); diff --git a/WebCore/rendering/HitTestRequest.h b/WebCore/rendering/HitTestRequest.h index 97d8680..745791a 100644 --- a/WebCore/rendering/HitTestRequest.h +++ b/WebCore/rendering/HitTestRequest.h @@ -35,7 +35,9 @@ public: SVGClipContent = 1 << 6 }; - HitTestRequest(int requestType) + typedef unsigned HitTestRequestType; + + HitTestRequest(HitTestRequestType requestType) : m_requestType(requestType) { } @@ -48,7 +50,7 @@ public: bool svgClipContent() const { return m_requestType & SVGClipContent; } private: - int m_requestType; + HitTestRequestType m_requestType; }; } // namespace WebCore diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp index 8d18440..2deeffc 100644 --- a/WebCore/rendering/RenderBox.cpp +++ b/WebCore/rendering/RenderBox.cpp @@ -73,10 +73,6 @@ bool RenderBox::s_hadOverflowClip = false; RenderBox::RenderBox(Node* node) : RenderBoxModelObject(node) -#ifdef ANDROID_LAYOUT - , m_visibleWidth(0) - , m_isVisibleWidthChangedBeforeLayout(false) -#endif , m_marginLeft(0) , m_marginRight(0) , m_marginTop(0) @@ -84,6 +80,10 @@ RenderBox::RenderBox(Node* node) , m_minPrefWidth(-1) , m_maxPrefWidth(-1) , m_inlineBoxWrapper(0) +#ifdef ANDROID_LAYOUT + , m_visibleWidth(0) + , m_isVisibleWidthChangedBeforeLayout(false) +#endif { setIsBox(); } diff --git a/WebCore/rendering/RenderBoxModelObject.cpp b/WebCore/rendering/RenderBoxModelObject.cpp index 077baeb..4ddd66b 100644 --- a/WebCore/rendering/RenderBoxModelObject.cpp +++ b/WebCore/rendering/RenderBoxModelObject.cpp @@ -1008,13 +1008,18 @@ void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx, graphicsContext->addPath(roundedPath); } + bool upperLeftBorderStylesMatch = renderLeft && (topStyle == leftStyle) && (topColor == leftColor); + bool upperRightBorderStylesMatch = renderRight && (topStyle == rightStyle) && (topColor == rightColor) && (topStyle != OUTSET) && (topStyle != RIDGE) && (topStyle != INSET) && (topStyle != GROOVE); + bool lowerLeftBorderStylesMatch = renderLeft && (bottomStyle == leftStyle) && (bottomColor == leftColor) && (bottomStyle != OUTSET) && (bottomStyle != RIDGE) && (bottomStyle != INSET) && (bottomStyle != GROOVE); + bool lowerRightBorderStylesMatch = renderRight && (bottomStyle == rightStyle) && (bottomColor == rightColor); + if (renderTop) { int x = tx; int x2 = tx + w; if (renderRadii && borderWillArcInnerEdge(topLeft, topRight, style->borderLeftWidth(), style->borderRightWidth(), style->borderTopWidth())) { graphicsContext->save(); - clipBorderSidePolygon(graphicsContext, borderRect, topLeft, topRight, bottomLeft, bottomRight, BSTop, style); + clipBorderSidePolygon(graphicsContext, borderRect, topLeft, topRight, bottomLeft, bottomRight, BSTop, upperLeftBorderStylesMatch, upperRightBorderStylesMatch, style); float thickness = max(max(style->borderTopWidth(), style->borderLeftWidth()), style->borderRightWidth()); drawBoxSideFromPath(graphicsContext, borderRect, roundedPath, style->borderTopWidth(), thickness, BSTop, style, topColor, topStyle); graphicsContext->restore(); @@ -1035,7 +1040,7 @@ void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx, if (renderRadii && borderWillArcInnerEdge(bottomLeft, bottomRight, style->borderLeftWidth(), style->borderRightWidth(), style->borderBottomWidth())) { graphicsContext->save(); - clipBorderSidePolygon(graphicsContext, borderRect, topLeft, topRight, bottomLeft, bottomRight, BSBottom, style); + clipBorderSidePolygon(graphicsContext, borderRect, topLeft, topRight, bottomLeft, bottomRight, BSBottom, lowerLeftBorderStylesMatch, lowerRightBorderStylesMatch, style); float thickness = max(max(style->borderBottomWidth(), style->borderLeftWidth()), style->borderRightWidth()); drawBoxSideFromPath(graphicsContext, borderRect, roundedPath, style->borderBottomWidth(), thickness, BSBottom, style, bottomColor, bottomStyle); graphicsContext->restore(); @@ -1058,7 +1063,7 @@ void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx, if (renderRadii && borderWillArcInnerEdge(bottomLeft, topLeft, style->borderBottomWidth(), style->borderTopWidth(), style->borderLeftWidth())) { graphicsContext->save(); - clipBorderSidePolygon(graphicsContext, borderRect, topLeft, topRight, bottomLeft, bottomRight, BSLeft, style); + clipBorderSidePolygon(graphicsContext, borderRect, topLeft, topRight, bottomLeft, bottomRight, BSLeft, upperLeftBorderStylesMatch, lowerLeftBorderStylesMatch, style); float thickness = max(max(style->borderLeftWidth(), style->borderTopWidth()), style->borderBottomWidth()); drawBoxSideFromPath(graphicsContext, borderRect, roundedPath, style->borderLeftWidth(), thickness, BSLeft, style, leftColor, leftStyle); graphicsContext->restore(); @@ -1077,7 +1082,7 @@ void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx, if (renderRight) { if (renderRadii && borderWillArcInnerEdge(bottomRight, topRight, style->borderBottomWidth(), style->borderTopWidth(), style->borderRightWidth())) { graphicsContext->save(); - clipBorderSidePolygon(graphicsContext, borderRect, topLeft, topRight, bottomLeft, bottomRight, BSRight, style); + clipBorderSidePolygon(graphicsContext, borderRect, topLeft, topRight, bottomLeft, bottomRight, BSRight, upperRightBorderStylesMatch, lowerRightBorderStylesMatch, style); float thickness = max(max(style->borderRightWidth(), style->borderTopWidth()), style->borderBottomWidth()); drawBoxSideFromPath(graphicsContext, borderRect, roundedPath, style->borderRightWidth(), thickness, BSRight, style, rightColor, rightStyle); graphicsContext->restore(); @@ -1455,7 +1460,7 @@ void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx, } #endif -void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext* graphicsContext, const IntRect& box, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const BoxSide side, const RenderStyle* style) +void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext* graphicsContext, const IntRect& box, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const BoxSide side, bool firstEdgeMatches, bool secondEdgeMatches, const RenderStyle* style) { FloatPoint quad[4]; int tx = box.x(); @@ -1510,7 +1515,28 @@ void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext* graphicsContex break; } - graphicsContext->clipConvexPolygon(4, quad); + // If the border matches both of its adjacent sides, don't anti-alias the clip, and + // if neither side matches, anti-alias the clip. + if (firstEdgeMatches == secondEdgeMatches) { + graphicsContext->clipConvexPolygon(4, quad, !firstEdgeMatches); + return; + } + + FloatPoint firstQuad[4]; + firstQuad[0] = quad[0]; + firstQuad[1] = quad[1]; + firstQuad[2] = side == BSTop || side == BSBottom ? FloatPoint(quad[3].x(), quad[2].y()) + : firstQuad[2] = FloatPoint(quad[2].x(), quad[3].y()); + firstQuad[3] = quad[3]; + graphicsContext->clipConvexPolygon(4, firstQuad, !firstEdgeMatches); + + FloatPoint secondQuad[4]; + secondQuad[0] = quad[0]; + secondQuad[1] = side == BSTop || side == BSBottom ? FloatPoint(quad[0].x(), quad[1].y()) + : FloatPoint(quad[1].x(), quad[0].y()); + secondQuad[2] = quad[2]; + secondQuad[3] = quad[3]; + graphicsContext->clipConvexPolygon(4, secondQuad, !secondEdgeMatches); } void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int ty, int w, int h, const RenderStyle* s, ShadowStyle shadowStyle, bool begin, bool end) diff --git a/WebCore/rendering/RenderBoxModelObject.h b/WebCore/rendering/RenderBoxModelObject.h index 45602f0..49d5f3d 100644 --- a/WebCore/rendering/RenderBoxModelObject.h +++ b/WebCore/rendering/RenderBoxModelObject.h @@ -115,7 +115,7 @@ private: IntSize calculateFillTileSize(const FillLayer*, IntSize scaledSize) const; - void clipBorderSidePolygon(GraphicsContext*, const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const BoxSide side, const RenderStyle* style); + void clipBorderSidePolygon(GraphicsContext*, const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const BoxSide side, bool firstEdgeMatches, bool secondEdgeMatches, const RenderStyle* style); friend class RenderView; diff --git a/WebCore/rendering/RenderInline.h b/WebCore/rendering/RenderInline.h index a719a50..71a8a89 100644 --- a/WebCore/rendering/RenderInline.h +++ b/WebCore/rendering/RenderInline.h @@ -74,6 +74,9 @@ public: int verticalPositionFromCache(bool firstLine) const; void invalidateVerticalPosition() { m_verticalPosition = PositionUndefined; } +protected: + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + private: virtual RenderObjectChildList* virtualChildren() { return children(); } virtual const RenderObjectChildList* virtualChildren() const { return children(); } @@ -139,7 +142,6 @@ private: virtual void addDashboardRegions(Vector<DashboardRegionValue>&); #endif - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual void updateBoxModelInfoFromStyle(); static RenderInline* cloneInline(RenderInline* src); diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp index f0c6333..756a9b3 100644 --- a/WebCore/rendering/RenderLayer.cpp +++ b/WebCore/rendering/RenderLayer.cpp @@ -1447,7 +1447,7 @@ void RenderLayer::scrollRectToVisible(const IntRect& rect, bool scrollToAnchor, newRect.setX(rect.x() - frameView->scrollX() + frameView->x()); newRect.setY(rect.y() - frameView->scrollY() + frameView->y()); } else { - IntRect viewRect = frameView->visibleContentRect(true); + IntRect viewRect = frameView->visibleContentRect(); IntRect r = getRectToExpose(viewRect, rect, alignX, alignY); frameView->setScrollPosition(r.location()); @@ -3238,16 +3238,18 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa if (renderer()->hasOverflowClip() || renderer()->hasClip()) { // This layer establishes a clip of some kind. #if ENABLE(ANDROID_OVERFLOW_SCROLL) - if (renderer()->hasOverflowClip()) { + if (renderer()->hasOverflowClip() && + !m_scrollDimensionsDirty && + (m_scrollWidth > renderBox()->clientWidth() || + m_scrollHeight > renderBox()->clientHeight())) { RenderBox* box = toRenderBox(renderer()); layerBounds = backgroundRect = foregroundRect = outlineRect = IntRect(x, y, box->borderLeft() + box->borderRight() + m_scrollWidth, box->borderTop() + box->borderBottom() + m_scrollHeight); - } -#else + } else +#endif if (renderer()->hasOverflowClip()) foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(x, y)); -#endif if (renderer()->hasClip()) { // Clip applies to *us* as well, so go ahead and update the damageRect. IntRect newPosClip = toRenderBox(renderer())->clipRect(x, y); @@ -3757,24 +3759,10 @@ bool RenderLayer::shouldBeNormalFlowOnly() const && !isTransparent(); } -#if ENABLE(ANDROID_OVERFLOW_SCROLL) -static bool hasOverflowScroll(const RenderLayer* layer) -{ - RenderBox* box = layer->renderBox(); - if (!box || !box->node() || !box->node()->hasTagName(HTMLNames::divTag)) - return false; - EOverflow x = box->style()->overflowX(); - EOverflow y = box->style()->overflowY(); - return (x == OAUTO || x == OSCROLL || y == OAUTO || y == OSCROLL) && - (box->scrollWidth() > box->clientWidth() || - box->scrollHeight() > box->clientHeight()); -} -#endif - bool RenderLayer::isSelfPaintingLayer() const { #if ENABLE(ANDROID_OVERFLOW_SCROLL) - if (hasOverflowScroll(this)) + if (renderer()->hasOverflowClip()) return true; #endif return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo() || renderer()->isEmbeddedObject() || renderer()->isRenderIFrame(); diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp index 2bc6a88..d66dfc2 100644 --- a/WebCore/rendering/RenderLayerBacking.cpp +++ b/WebCore/rendering/RenderLayerBacking.cpp @@ -144,19 +144,14 @@ static bool hasNonZeroTransformOrigin(const RenderObject* renderer) || (style->transformOriginY().type() == Fixed && style->transformOriginY().value()); } -static RenderLayer* enclosingOverflowClipAncestor(RenderLayer* layer, bool& crossesTransform) +static bool layerOrAncestorIsTransformed(RenderLayer* layer) { - crossesTransform = false; - - for (RenderLayer* curr = layer->parent(); curr; curr = curr->parent()) { - if (curr->renderer()->hasOverflowClip()) - return curr; - + for (RenderLayer* curr = layer; curr; curr = curr->parent()) { if (curr->hasTransform()) - crossesTransform = true; + return true; } - return 0; + return false; } void RenderLayerBacking::updateCompositedBounds() @@ -164,38 +159,24 @@ 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 this or 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 (compositor()->compositingConsultsOverlap() && !layerOrAncestorIsTransformed(m_owningLayer)) { + RenderView* view = m_owningLayer->renderer()->view(); + RenderLayer* rootLayer = view->layer(); + + // Start by clipping to the view's bounds. + IntRect clippingBounds = view->layoutOverflowRect(); + + if (m_owningLayer != rootLayer) + clippingBounds.intersect(m_owningLayer->backgroundClipRect(rootLayer, true)); + + int deltaX = 0; + int deltaY = 0; + m_owningLayer->convertToLayerCoords(rootLayer, 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, @@ -215,7 +196,7 @@ void RenderLayerBacking::updateAfterWidgetResize() { if (renderer()->isRenderIFrame()) { if (RenderLayerCompositor* innerCompositor = RenderLayerCompositor::iframeContentsCompositor(toRenderIFrame(renderer()))) - innerCompositor->updateContentLayerOffset(contentsBox().location()); + innerCompositor->frameViewDidChangeSize(contentsBox().location()); } } diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp index 46278a2..3d16864 100644 --- a/WebCore/rendering/RenderLayerCompositor.cpp +++ b/WebCore/rendering/RenderLayerCompositor.cpp @@ -826,7 +826,7 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, cons } } -void RenderLayerCompositor::updateContentLayerOffset(const IntPoint& contentsOffset) +void RenderLayerCompositor::frameViewDidChangeSize(const IntPoint& contentsOffset) { if (m_clipLayer) { FrameView* frameView = m_renderView->frameView(); @@ -838,7 +838,7 @@ void RenderLayerCompositor::updateContentLayerOffset(const IntPoint& contentsOff } } -void RenderLayerCompositor::updateContentLayerScrollPosition(const IntPoint& scrollPosition) +void RenderLayerCompositor::frameViewDidScroll(const IntPoint& scrollPosition) { if (m_scrollLayer) m_scrollLayer->setPosition(FloatPoint(-scrollPosition.x(), -scrollPosition.y())); @@ -1082,6 +1082,10 @@ bool RenderLayerCompositor::shouldPropagateCompositingToEnclosingIFrame() const // On non-Mac platforms, let compositing propagate for all iframes. return true; #else + // If we're viewless (i.e. WebKit2), we always propagate compositing. + if (!m_renderView->frameView()->platformWidget()) + return true; + // On Mac, only propagate compositing if the iframe is overlapped in the parent // document, or the parent is already compositing. RenderIFrame* iframeRenderer = toRenderIFrame(renderer); @@ -1155,19 +1159,6 @@ bool RenderLayerCompositor::requiresCompositingForMobileSites(const RenderLayer* } #endif -#if ENABLE(ANDROID_OVERFLOW_SCROLL) -static bool requiresCompositingForOverflowScroll(const RenderLayer* layer) { - RenderBox* box = layer->renderBox(); - if (!box || !box->node()->hasTagName(HTMLNames::divTag)) - return false; - EOverflow x = box->style()->overflowX(); - EOverflow y = box->style()->overflowY(); - return (x == OAUTO || x == OSCROLL || y == OAUTO || y == OSCROLL) && - (box->scrollWidth() > box->clientWidth() || - box->scrollHeight() > box->clientHeight()); -} -#endif - // Note: this specifies whether the RL needs a compositing layer for intrinsic reasons. // Use needsToBeComposited() to determine if a RL actually needs a compositing layer. // static @@ -1183,7 +1174,7 @@ bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) c #if PLATFORM(ANDROID) || requiresCompositingForMobileSites(layer) #if ENABLE(ANDROID_OVERFLOW_SCROLL) - || requiresCompositingForOverflowScroll(layer) + || renderer->hasOverflowClip() #endif #endif || requiresCompositingForVideo(renderer) @@ -1358,6 +1349,20 @@ bool RenderLayerCompositor::needsContentsCompositingLayer(const RenderLayer* lay return (layer->m_negZOrderList && layer->m_negZOrderList->size() > 0); } +bool RenderLayerCompositor::requiresScrollLayer(RootLayerAttachment attachment) const +{ + if (attachment == RootLayerAttachedViaEnclosingIframe) + return true; + +#if PLATFORM(MAC) + // If we're viewless (i.e. WebKit2), we need to scroll ourselves. + // FIXME: eventually we should do this on other platforms too. + if (!m_renderView->frameView()->platformWidget()) + return true; +#endif + return false; +} + void RenderLayerCompositor::ensureRootPlatformLayer() { RootLayerAttachment expectedAttachment = shouldPropagateCompositingToEnclosingIFrame() ? RootLayerAttachedViaEnclosingIframe : RootLayerAttachedViaChromeClient; @@ -1376,10 +1381,7 @@ void RenderLayerCompositor::ensureRootPlatformLayer() m_rootPlatformLayer->setMasksToBounds(true); } - // The root layer does flipping if we need it on this platform. - m_rootPlatformLayer->setGeometryOrientation(expectedAttachment == RootLayerAttachedViaEnclosingIframe ? GraphicsLayer::CompositingCoordinatesTopDown : GraphicsLayer::compositingCoordinatesOrientation()); - - if (expectedAttachment == RootLayerAttachedViaEnclosingIframe) { + if (requiresScrollLayer(expectedAttachment)) { if (!m_clipLayer) { ASSERT(!m_scrollLayer); // Create a clipping layer if this is an iframe @@ -1397,17 +1399,24 @@ void RenderLayerCompositor::ensureRootPlatformLayer() m_clipLayer->addChild(m_scrollLayer.get()); m_scrollLayer->addChild(m_rootPlatformLayer.get()); - updateContentLayerScrollPosition(m_renderView->frameView()->scrollPosition()); + frameViewDidChangeSize(); + frameViewDidScroll(m_renderView->frameView()->scrollPosition()); + } + } else { + if (m_clipLayer) { + m_clipLayer->removeAllChildren(); + m_clipLayer->removeFromParent(); + m_clipLayer = 0; + + m_scrollLayer->removeAllChildren(); + m_scrollLayer = 0; } - } else if (m_clipLayer) { - m_clipLayer->removeAllChildren(); - m_clipLayer->removeFromParent(); - m_clipLayer = 0; - - m_scrollLayer->removeAllChildren(); - m_scrollLayer = 0; } + // The root layer does geometry flipping if we need it. + m_rootPlatformLayer->setGeometryOrientation(expectedAttachment == RootLayerAttachedViaEnclosingIframe + ? GraphicsLayer::CompositingCoordinatesTopDown : GraphicsLayer::compositingCoordinatesOrientation()); + // Check to see if we have to change the attachment if (m_rootLayerAttachment != RootLayerUnattached) detachRootPlatformLayer(); @@ -1447,7 +1456,7 @@ void RenderLayerCompositor::attachRootPlatformLayer(RootLayerAttachment attachme if (!page) return; - page->chrome()->client()->attachRootGraphicsLayer(frame, m_rootPlatformLayer.get()); + page->chrome()->client()->attachRootGraphicsLayer(frame, rootPlatformLayer()); break; } case RootLayerAttachedViaEnclosingIframe: { diff --git a/WebCore/rendering/RenderLayerCompositor.h b/WebCore/rendering/RenderLayerCompositor.h index 10516ad..67623d4 100644 --- a/WebCore/rendering/RenderLayerCompositor.h +++ b/WebCore/rendering/RenderLayerCompositor.h @@ -158,8 +158,8 @@ public: static bool parentIFrameContentLayers(RenderIFrame*); // Update the geometry of the layers used for clipping and scrolling in frames. - void updateContentLayerOffset(const IntPoint& contentsOffset); - void updateContentLayerScrollPosition(const IntPoint&); + void frameViewDidChangeSize(const IntPoint& contentsOffset = IntPoint()); + void frameViewDidScroll(const IntPoint& = IntPoint()); private: // Whether the given RL needs a compositing layer. @@ -219,6 +219,8 @@ private: bool requiresCompositingForMobileSites(const RenderLayer* layer) const; #endif + bool requiresScrollLayer(RootLayerAttachment) const; + private: RenderView* m_renderView; OwnPtr<GraphicsLayer> m_rootPlatformLayer; diff --git a/WebCore/rendering/RenderMediaControlsChromium.cpp b/WebCore/rendering/RenderMediaControlsChromium.cpp index 98fdc7b..ab650da 100644 --- a/WebCore/rendering/RenderMediaControlsChromium.cpp +++ b/WebCore/rendering/RenderMediaControlsChromium.cpp @@ -96,7 +96,7 @@ static bool paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInf if (!hasSource(mediaElement)) return paintMediaButton(paintInfo.context, rect, mediaPlayDisabled); - return paintMediaButton(paintInfo.context, rect, mediaElement->paused() ? mediaPlay : mediaPause); + return paintMediaButton(paintInfo.context, rect, mediaElement->canPlay() ? mediaPlay : mediaPause); } static Image* getMediaSliderThumb() diff --git a/WebCore/rendering/RenderMenuList.cpp b/WebCore/rendering/RenderMenuList.cpp index 177921c..ff16e7e 100644 --- a/WebCore/rendering/RenderMenuList.cpp +++ b/WebCore/rendering/RenderMenuList.cpp @@ -354,6 +354,11 @@ String RenderMenuList::itemLabel(unsigned) const return String(); } +String RenderMenuList::itemIcon(unsigned) const +{ + return String(); +} + String RenderMenuList::itemAccessibilityText(unsigned listIndex) const { // Allow the accessible name be changed if necessary. diff --git a/WebCore/rendering/RenderMenuList.h b/WebCore/rendering/RenderMenuList.h index d72e1a9..aef8d4f 100644 --- a/WebCore/rendering/RenderMenuList.h +++ b/WebCore/rendering/RenderMenuList.h @@ -83,6 +83,7 @@ private: // PopupMenuClient methods virtual String itemText(unsigned listIndex) const; virtual String itemLabel(unsigned listIndex) const; + virtual String itemIcon(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/RenderSVGAllInOne.cpp b/WebCore/rendering/RenderSVGAllInOne.cpp index da86f84..fa5709e 100644 --- a/WebCore/rendering/RenderSVGAllInOne.cpp +++ b/WebCore/rendering/RenderSVGAllInOne.cpp @@ -35,6 +35,7 @@ #include "RenderSVGModelObject.cpp" #include "RenderSVGResource.cpp" #include "RenderSVGResourceClipper.cpp" +#include "RenderSVGResourceContainer.cpp" #include "RenderSVGResourceFilter.cpp" #include "RenderSVGResourceGradient.cpp" #include "RenderSVGResourceLinearGradient.cpp" @@ -57,6 +58,9 @@ #include "SVGMarkerLayoutInfo.cpp" #include "SVGRenderSupport.cpp" #include "SVGRenderTreeAsText.cpp" +#include "SVGResources.cpp" +#include "SVGResourcesCache.cpp" +#include "SVGResourcesCycleSolver.cpp" #include "SVGRootInlineBox.cpp" #include "SVGShadowTreeElements.cpp" #include "SVGTextChunkLayoutInfo.cpp" diff --git a/WebCore/rendering/RenderSVGHiddenContainer.h b/WebCore/rendering/RenderSVGHiddenContainer.h index c446f11..297a738 100644 --- a/WebCore/rendering/RenderSVGHiddenContainer.h +++ b/WebCore/rendering/RenderSVGHiddenContainer.h @@ -37,11 +37,10 @@ namespace WebCore { public: RenderSVGHiddenContainer(SVGStyledElement*); - private: - virtual bool isSVGHiddenContainer() const { return true; } - virtual const char* renderName() const { return "RenderSVGHiddenContainer"; } + private: + virtual bool isSVGHiddenContainer() const { return true; } virtual bool requiresLayer() const { return false; } virtual void layout(); diff --git a/WebCore/rendering/RenderSVGResourceContainer.cpp b/WebCore/rendering/RenderSVGResourceContainer.cpp new file mode 100644 index 0000000..3707797 --- /dev/null +++ b/WebCore/rendering/RenderSVGResourceContainer.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceContainer.h" + +#include "RenderSVGShadowTreeRootContainer.h" +#include "SVGStyledTransformableElement.h" + +namespace WebCore { + +RenderSVGResourceContainer::RenderSVGResourceContainer(SVGStyledElement* node) + : RenderSVGHiddenContainer(node) + , RenderSVGResource() + , m_id(node->hasID() ? node->getIdAttribute() : nullAtom) +{ + ASSERT(node->document()); + node->document()->accessSVGExtensions()->addResource(m_id, this); +} + +RenderSVGResourceContainer::~RenderSVGResourceContainer() +{ + ASSERT(node()); + ASSERT(node()->document()); + node()->document()->accessSVGExtensions()->removeResource(m_id); +} + +void RenderSVGResourceContainer::idChanged() +{ + ASSERT(node()); + ASSERT(node()->document()); + SVGDocumentExtensions* extensions = node()->document()->accessSVGExtensions(); + + // Remove old id, that is guaranteed to be present in cache + extensions->removeResource(m_id); + m_id = static_cast<Element*>(node())->getIdAttribute(); + + // It's possible that an element is referencing us with the new id, and has to be notified that we're existing now + if (extensions->isPendingResource(m_id)) { + OwnPtr<HashSet<SVGStyledElement*> > clients(extensions->removePendingResource(m_id)); + if (clients->isEmpty()) + return; + + HashSet<SVGStyledElement*>::const_iterator it = clients->begin(); + const HashSet<SVGStyledElement*>::const_iterator end = clients->end(); + + for (; it != end; ++it) { + if (RenderObject* renderer = (*it)->renderer()) + renderer->setNeedsLayout(true); + } + } + + // Recache us with the new id + extensions->addResource(m_id, this); +} + +AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderObject* object, const AffineTransform& resourceTransform) +{ + if (!object->isRenderPath()) + return resourceTransform; + + SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(object->node()); + AffineTransform transform = resourceTransform; + transform.multiply(element->getScreenCTM()); + return transform; +} + +bool RenderSVGResourceContainer::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; +} + +} + +#endif diff --git a/WebCore/rendering/RenderSVGResourceContainer.h b/WebCore/rendering/RenderSVGResourceContainer.h index 5f1c828..d57b1db 100644 --- a/WebCore/rendering/RenderSVGResourceContainer.h +++ b/WebCore/rendering/RenderSVGResourceContainer.h @@ -33,50 +33,10 @@ namespace WebCore { class RenderSVGResourceContainer : public RenderSVGHiddenContainer, public RenderSVGResource { public: - RenderSVGResourceContainer(SVGStyledElement* node) - : RenderSVGHiddenContainer(node) - , RenderSVGResource() - , m_id(node->hasID() ? node->getIdAttribute() : nullAtom) - { - ASSERT(node->document()); - node->document()->accessSVGExtensions()->addResource(m_id, this); - } - - virtual ~RenderSVGResourceContainer() - { - ASSERT(node()); - ASSERT(node()->document()); - node()->document()->accessSVGExtensions()->removeResource(m_id); - } - - void idChanged() - { - ASSERT(node()); - ASSERT(node()->document()); - SVGDocumentExtensions* extensions = node()->document()->accessSVGExtensions(); - - // Remove old id, that is guaranteed to be present in cache - extensions->removeResource(m_id); - m_id = static_cast<Element*>(node())->getIdAttribute(); - - // It's possible that an element is referencing us with the new id, and has to be notified that we're existing now - if (extensions->isPendingResource(m_id)) { - OwnPtr<HashSet<SVGStyledElement*> > clients(extensions->removePendingResource(m_id)); - if (clients->isEmpty()) - return; - - HashSet<SVGStyledElement*>::const_iterator it = clients->begin(); - const HashSet<SVGStyledElement*>::const_iterator end = clients->end(); - - for (; it != end; ++it) { - if (RenderObject* renderer = (*it)->renderer()) - renderer->setNeedsLayout(true); - } - } - - // Recache us with the new id - extensions->addResource(m_id, this); - } + RenderSVGResourceContainer(SVGStyledElement*); + virtual ~RenderSVGResourceContainer(); + + void idChanged(); virtual bool isSVGResourceContainer() const { return true; } virtual bool drawsContents() { return false; } @@ -84,58 +44,16 @@ public: 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()) - return resourceTransform; - - SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(object->node()); - AffineTransform transform = resourceTransform; - transform.multiply(element->getScreenCTM()); - 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; - } + static AffineTransform transformOnNonScalingStroke(RenderObject*, const AffineTransform& resourceTransform); + + bool containsCyclicReference(const Node* startNode) const; + +private: + friend class SVGResourcesCache; + + // FIXME: No-ops for now, until follow-up patch on bug 43031 lands. + void addClient(RenderObject*) { } + void removeClient(RenderObject*) { } private: AtomicString m_id; diff --git a/WebCore/rendering/RenderTable.cpp b/WebCore/rendering/RenderTable.cpp index 52fc326..6359c09 100644 --- a/WebCore/rendering/RenderTable.cpp +++ b/WebCore/rendering/RenderTable.cpp @@ -618,7 +618,7 @@ void RenderTable::splitColumn(int pos, int firstSpan) // change width of all rows. for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isTableSection()) - toRenderTableSection(child)->splitColumn(pos, oldSize + 1); + toRenderTableSection(child)->splitColumn(pos, firstSpan); } m_columnPos.grow(numEffCols() + 1); @@ -812,12 +812,12 @@ int RenderTable::calcBorderLeft() const const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, leftmostColumn); - if (cs.cell) { - const BorderValue& cb = cs.cell->style()->borderLeft(); + if (cs.hasCells()) { + const BorderValue& cb = cs.primaryCell()->style()->borderLeft(); if (cb.style() == BHIDDEN) return 0; - const BorderValue& rb = cs.cell->parent()->style()->borderLeft(); + const BorderValue& rb = cs.primaryCell()->parent()->style()->borderLeft(); if (rb.style() == BHIDDEN) return 0; @@ -871,12 +871,12 @@ int RenderTable::calcBorderRight() const const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, rightmostColumn); - if (cs.cell) { - const BorderValue& cb = cs.cell->style()->borderRight(); + if (cs.hasCells()) { + const BorderValue& cb = cs.primaryCell()->style()->borderRight(); if (cb.style() == BHIDDEN) return 0; - const BorderValue& rb = cs.cell->parent()->style()->borderRight(); + const BorderValue& rb = cs.primaryCell()->parent()->style()->borderRight(); if (rb.style() == BHIDDEN) return 0; @@ -1081,13 +1081,8 @@ RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const // Look up the cell in the section's grid, which requires effective col index if (section) { int effCol = colToEffCol(cell->col()); - RenderTableSection::CellStruct aboveCell; - // If we hit a span back up to a real cell. - do { - aboveCell = section->cellAt(rAbove, effCol); - effCol--; - } while (!aboveCell.cell && aboveCell.inColSpan && effCol >= 0); - return aboveCell.cell; + RenderTableSection::CellStruct& aboveCell = section->cellAt(rAbove, effCol); + return aboveCell.primaryCell(); } else return 0; } @@ -1113,13 +1108,8 @@ RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const // Look up the cell in the section's grid, which requires effective col index if (section) { int effCol = colToEffCol(cell->col()); - RenderTableSection::CellStruct belowCell; - // If we hit a colspan back up to a real cell. - do { - belowCell = section->cellAt(rBelow, effCol); - effCol--; - } while (!belowCell.cell && belowCell.inColSpan && effCol >= 0); - return belowCell.cell; + RenderTableSection::CellStruct& belowCell = section->cellAt(rBelow, effCol); + return belowCell.primaryCell(); } else return 0; } @@ -1134,12 +1124,8 @@ RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const return 0; // If we hit a colspan back up to a real cell. - RenderTableSection::CellStruct prevCell; - do { - prevCell = section->cellAt(cell->row(), effCol - 1); - effCol--; - } while (!prevCell.cell && prevCell.inColSpan && effCol >= 0); - return prevCell.cell; + RenderTableSection::CellStruct& prevCell = section->cellAt(cell->row(), effCol - 1); + return prevCell.primaryCell(); } RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const @@ -1149,7 +1135,7 @@ RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const int effCol = colToEffCol(cell->col() + cell->colSpan()); if (effCol >= numEffCols()) return 0; - return cell->section()->cellAt(cell->row(), effCol).cell; + return cell->section()->primaryCellAt(cell->row(), effCol); } RenderBlock* RenderTable::firstLineBlock() const diff --git a/WebCore/rendering/RenderTableSection.cpp b/WebCore/rendering/RenderTableSection.cpp index fcb6c59..c439a13 100644 --- a/WebCore/rendering/RenderTableSection.cpp +++ b/WebCore/rendering/RenderTableSection.cpp @@ -37,6 +37,7 @@ #include "RenderTableRow.h" #include "RenderView.h" #include <limits> +#include <wtf/HashSet.h> #include <wtf/Vector.h> #ifdef ANDROID_LAYOUT #include "Frame.h" @@ -68,9 +69,10 @@ RenderTableSection::RenderTableSection(Node* node) , m_outerBorderBottom(0) , m_needsCellRecalc(false) , m_hasOverflowingCell(false) + , m_hasMultipleCellLevels(false) { // init RenderObject attributes - setInline(false); // our object is not Inline + setInline(false); // our object is not Inline } RenderTableSection::~RenderTableSection() @@ -166,12 +168,8 @@ bool RenderTableSection::ensureRows(int numRows) } m_gridRows = numRows; int nCols = max(1, table()->numEffCols()); - CellStruct emptyCellStruct; - emptyCellStruct.cell = 0; - emptyCellStruct.inColSpan = false; for (int r = nRows; r < numRows; r++) { m_grid[r].row = new Row(nCols); - m_grid[r].row->fill(emptyCellStruct); m_grid[r].rowRenderer = 0; m_grid[r].baseline = 0; m_grid[r].height = Length(); @@ -194,8 +192,7 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row) // <TR><TD>1 <TD rowspan="2">2 <TD>3 <TD>4 // <TR><TD colspan="2">5 // </TABLE> - - while (m_cCol < nCols && (cellAt(m_cRow, m_cCol).cell || cellAt(m_cRow, m_cCol).inColSpan)) + while (m_cCol < nCols && (cellAt(m_cRow, m_cCol).hasCells() || cellAt(m_cRow, m_cCol).inColSpan)) m_cCol++; if (rSpan == 1) { @@ -229,31 +226,30 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row) int col = m_cCol; // tell the cell where it is - CellStruct currentCell; - currentCell.cell = cell; - currentCell.inColSpan = false; + bool inColSpan = false; while (cSpan) { int currentSpan; if (m_cCol >= nCols) { table()->appendColumn(cSpan); currentSpan = cSpan; } else { - if (cSpan < static_cast<int>(columns[m_cCol].span)) + if (cSpan < (int)columns[m_cCol].span) table()->splitColumn(m_cCol, cSpan); currentSpan = columns[m_cCol].span; } - for (int r = 0; r < rSpan; r++) { CellStruct& c = cellAt(m_cRow + r, m_cCol); - if (!c.cell) - c.cell = currentCell.cell; - if (currentCell.inColSpan) + ASSERT(cell); + c.cells.append(cell); + // If cells overlap then we take the slow path for painting. + if (c.cells.size() > 1) + m_hasMultipleCellLevels = true; + if (inColSpan) c.inColSpan = true; } m_cCol++; cSpan -= currentSpan; - currentCell.cell = 0; - currentCell.inColSpan = true; + inColSpan = true; } cell->setRow(m_cRow); cell->setCol(table()->effColToCol(col)); @@ -279,14 +275,14 @@ void RenderTableSection::setCellWidths() Row& row = *m_grid[i].row; int cols = row.size(); for (int j = 0; j < cols; j++) { - CellStruct current = row[j]; - RenderTableCell* cell = current.cell; - - if (!cell) - continue; + CellStruct& current = row[j]; + RenderTableCell* cell = current.primaryCell(); + if (!cell || current.inColSpan) + continue; int endCol = j; int cspan = cell->colSpan(); while (cspan && endCol < cols) { + ASSERT(endCol < (int)table()->columns().size()); cspan -= table()->columns()[endCol].span; endCol++; } @@ -321,7 +317,7 @@ void RenderTableSection::setCellWidths() } } - statePusher.pop(); // only pops if we pushed + statePusher.pop(); // only pops if we pushed } int RenderTableSection::calcRowHeight() @@ -364,11 +360,13 @@ int RenderTableSection::calcRowHeight() int totalCols = row->size(); for (int c = 0; c < totalCols; c++) { - CellStruct current = cellAt(r, c); - cell = current.cell; + CellStruct& current = cellAt(r, c); + cell = current.primaryCell(); + if (!cell || current.inColSpan) continue; - if (r < m_gridRows - 1 && cellAt(r + 1, c).cell == cell) + + if ((cell->row() + cell->rowSpan() - 1) > r) continue; int indx = max(r - cell->rowSpan() + 1, 0); @@ -410,7 +408,7 @@ int RenderTableSection::calcRowHeight() } } - //do we have baseline aligned elements? + // do we have baseline aligned elements? if (baseline) { // increase rowheight if baseline requires m_rowPos[r + 1] = max(m_rowPos[r + 1], baseline + bdesc + (m_grid[r].rowRenderer ? spacing : 0)); @@ -466,11 +464,11 @@ int RenderTableSection::layoutRows(int toAdd) for (int r = 0; r < totalRows; r++) { for (int c = 0; c < nEffCols; c++) { CellStruct current = cellAt(r, c); - RenderTableCell* cell = current.cell; + RenderTableCell* cell = current.primaryCell(); if (!cell || current.inColSpan) continue; - if (r > 0 && (cellAt(r-1, c).cell == cell)) + if (r > 0 && (primaryCellAt(r-1, c) == cell)) continue; // cell->setCellTopExtra(0); @@ -564,7 +562,7 @@ int RenderTableSection::layoutRows(int toAdd) int add = 0; int prev = m_rowPos[0]; for (int r = 0; r < totalRows; r++) { - //weight with the original height + // weight with the original height add += dh * (m_rowPos[r + 1] - prev) / tot; prev = m_rowPos[r + 1]; m_rowPos[r + 1] += add; @@ -587,16 +585,14 @@ int RenderTableSection::layoutRows(int toAdd) } for (int c = 0; c < nEffCols; c++) { - RenderTableCell* cell = cellAt(r, c).cell; - - if (!cell) - continue; - if (r < totalRows - 1 && cell == cellAt(r + 1, c).cell) - continue; + CellStruct& cs = cellAt(r, c); + RenderTableCell* cell = cs.primaryCell(); - rindx = max(0, r - cell->rowSpan() + 1); + if (!cell || cs.inColSpan) + continue; - rHeight = m_rowPos[r + 1] - m_rowPos[rindx] - vspacing; + rindx = cell->row(); + rHeight = m_rowPos[rindx + cell->rowSpan()] - m_rowPos[rindx] - vspacing; // Force percent height children to lay themselves out again. // This will cause these children to grow to fill the cell. @@ -612,8 +608,8 @@ int RenderTableSection::layoutRows(int toAdd) // match the behavior perfectly, but we'll continue to refine it as we discover new // bugs. :) bool cellChildrenFlex = false; - bool flexAllChildren = cell->style()->height().isFixed() || - (!table()->style()->height().isAuto() && rHeight != cell->height()); + bool flexAllChildren = cell->style()->height().isFixed() + || (!table()->style()->height().isAuto() && rHeight != cell->height()); for (RenderObject* o = cell->firstChild(); o; o = o->nextSibling()) { if (!o->isText() && o->style()->height().isPercent() && (flexAllChildren || o->isReplaced() || (o->isBox() && toRenderBox(o)->scrollsOverflow()))) { @@ -706,9 +702,9 @@ int RenderTableSection::layoutRows(int toAdd) IntRect oldCellRect(cell->x(), cell->y() , cell->width(), cell->height()); - if (style()->direction() == RTL) { + if (style()->direction() == RTL) cell->setLocation(table()->columnPositions()[nEffCols] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + hspacing, m_rowPos[rindx]); - } else + else cell->setLocation(table()->columnPositions()[c] + hspacing, m_rowPos[rindx]); // If the cell moved, we have to repaint it as well as any floating/positioned @@ -730,10 +726,11 @@ int RenderTableSection::layoutRows(int toAdd) // Now that our height has been determined, add in overflow from cells. for (int r = 0; r < totalRows; r++) { for (int c = 0; c < nEffCols; c++) { - RenderTableCell* cell = cellAt(r, c).cell; - if (!cell) + CellStruct& cs = cellAt(r, c); + RenderTableCell* cell = cs.primaryCell(); + if (!cell || cs.inColSpan) continue; - if (r < totalRows - 1 && cell == cellAt(r + 1, c).cell) + if (r < totalRows - 1 && cell == primaryCellAt(r + 1, c)) continue; addOverflowFromChild(cell); m_hasOverflowingCell |= cell->hasVisibleOverflow(); @@ -821,17 +818,16 @@ int RenderTableSection::calcOuterBorderTop() const bool allHidden = true; for (int c = 0; c < totalCols; c++) { const CellStruct& current = cellAt(0, c); - if (current.inColSpan || !current.cell) + if (current.inColSpan || !current.hasCells()) continue; - const BorderValue& cb = current.cell->style()->borderTop(); + const BorderValue& cb = current.primaryCell()->style()->borderTop(); // FIXME: Don't repeat for the same col group RenderTableCol* colGroup = table()->colElement(c); if (colGroup) { const BorderValue& gb = colGroup->style()->borderTop(); if (gb.style() == BHIDDEN || cb.style() == BHIDDEN) continue; - else - allHidden = false; + allHidden = false; if (gb.style() > BHIDDEN && gb.width() > borderWidth) borderWidth = gb.width(); if (cb.style() > BHIDDEN && cb.width() > borderWidth) @@ -839,8 +835,7 @@ int RenderTableSection::calcOuterBorderTop() const } else { if (cb.style() == BHIDDEN) continue; - else - allHidden = false; + allHidden = false; if (cb.style() > BHIDDEN && cb.width() > borderWidth) borderWidth = cb.width(); } @@ -874,17 +869,16 @@ int RenderTableSection::calcOuterBorderBottom() const bool allHidden = true; for (int c = 0; c < totalCols; c++) { const CellStruct& current = cellAt(m_gridRows - 1, c); - if (current.inColSpan || !current.cell) + if (current.inColSpan || !current.hasCells()) continue; - const BorderValue& cb = current.cell->style()->borderBottom(); + const BorderValue& cb = current.primaryCell()->style()->borderBottom(); // FIXME: Don't repeat for the same col group RenderTableCol* colGroup = table()->colElement(c); if (colGroup) { const BorderValue& gb = colGroup->style()->borderBottom(); if (gb.style() == BHIDDEN || cb.style() == BHIDDEN) continue; - else - allHidden = false; + allHidden = false; if (gb.style() > BHIDDEN && gb.width() > borderWidth) borderWidth = gb.width(); if (cb.style() > BHIDDEN && cb.width() > borderWidth) @@ -892,8 +886,7 @@ int RenderTableSection::calcOuterBorderBottom() const } else { if (cb.style() == BHIDDEN) continue; - else - allHidden = false; + allHidden = false; if (cb.style() > BHIDDEN && cb.width() > borderWidth) borderWidth = cb.width(); } @@ -931,15 +924,14 @@ int RenderTableSection::calcOuterBorderLeft(bool rtl) const bool allHidden = true; for (int r = 0; r < m_gridRows; r++) { const CellStruct& current = cellAt(r, leftmostColumn); - if (!current.cell) + if (!current.hasCells()) continue; // FIXME: Don't repeat for the same cell - const BorderValue& cb = current.cell->style()->borderLeft(); - const BorderValue& rb = current.cell->parent()->style()->borderLeft(); + const BorderValue& cb = current.primaryCell()->style()->borderLeft(); + const BorderValue& rb = current.primaryCell()->parent()->style()->borderLeft(); if (cb.style() == BHIDDEN || rb.style() == BHIDDEN) continue; - else - allHidden = false; + allHidden = false; if (cb.style() > BHIDDEN && cb.width() > borderWidth) borderWidth = cb.width(); if (rb.style() > BHIDDEN && rb.width() > borderWidth) @@ -978,15 +970,14 @@ int RenderTableSection::calcOuterBorderRight(bool rtl) const bool allHidden = true; for (int r = 0; r < m_gridRows; r++) { const CellStruct& current = cellAt(r, rightmostColumn); - if (!current.cell) + if (!current.hasCells()) continue; // FIXME: Don't repeat for the same cell - const BorderValue& cb = current.cell->style()->borderRight(); - const BorderValue& rb = current.cell->parent()->style()->borderRight(); + const BorderValue& cb = current.primaryCell()->style()->borderRight(); + const BorderValue& rb = current.primaryCell()->parent()->style()->borderRight(); if (cb.style() == BHIDDEN || rb.style() == BHIDDEN) continue; - else - allHidden = false; + allHidden = false; if (cb.style() > BHIDDEN && cb.width() > borderWidth) borderWidth = cb.width(); if (rb.style() > BHIDDEN && rb.width() > borderWidth) @@ -1019,7 +1010,8 @@ int RenderTableSection::firstLineBoxBaseline() const firstLineBaseline = -1; Row* firstRow = m_grid[0].row; for (size_t i = 0; i < firstRow->size(); ++i) { - RenderTableCell* cell = firstRow->at(i).cell; + CellStruct& cs = firstRow->at(i); + RenderTableCell* cell = cs.primaryCell(); if (cell) firstLineBaseline = max(firstLineBaseline, cell->y() + cell->paddingTop() + cell->borderTop() + cell->contentHeight()); } @@ -1051,6 +1043,45 @@ void RenderTableSection::paint(PaintInfo& paintInfo, int tx, int ty) popContentsClip(paintInfo, phase, tx, ty); } +static inline bool compareCellPositions(RenderTableCell* elem1, RenderTableCell* elem2) +{ + return elem1->row() < elem2->row(); +} + +void RenderTableSection::paintCell(RenderTableCell* cell, PaintInfo& paintInfo, int tx, int ty) +{ + PaintPhase paintPhase = paintInfo.phase; + RenderTableRow* row = toRenderTableRow(cell->parent()); + + if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) { + // We need to handle painting a stack of backgrounds. This stack (from bottom to top) consists of + // the column group, column, row group, row, and then the cell. + RenderObject* col = table()->colElement(cell->col()); + RenderObject* colGroup = 0; + if (col && col->parent()->style()->display() == TABLE_COLUMN_GROUP) + colGroup = col->parent(); + + // Column groups and columns first. + // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in + // the stack, since we have already opened a transparency layer (potentially) for the table row group. + // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the + // cell. + cell->paintBackgroundsBehindCell(paintInfo, tx, ty, colGroup); + cell->paintBackgroundsBehindCell(paintInfo, tx, ty, col); + + // Paint the row group next. + cell->paintBackgroundsBehindCell(paintInfo, tx, ty, this); + + // Paint the row next, but only if it doesn't have a layer. If a row has a layer, it will be responsible for + // painting the row background for the cell. + if (!row->hasSelfPaintingLayer()) + cell->paintBackgroundsBehindCell(paintInfo, tx, ty, row); + } + if ((!cell->hasSelfPaintingLayer() && !row->hasSelfPaintingLayer()) || paintInfo.phase == PaintPhaseCollapsedTableBorders) + cell->paint(paintInfo, tx, ty); + +} + void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty) { // Check which rows and cols are visible and only paint these. @@ -1120,57 +1151,48 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty) if (!endcol && tx + table()->columnPositions()[0] - table()->outerBorderLeft() <= y + w + os) endcol++; } + #ifdef ANDROID_LAYOUT } #endif if (startcol < endcol) { - // draw the cells - for (unsigned r = startrow; r < endrow; r++) { - unsigned c = startcol; - // since a cell can be -1 (indicating a colspan) we might have to search backwards to include it - while (c && cellAt(r, c).inColSpan) - c--; - for (; c < endcol; c++) { - CellStruct current = cellAt(r, c); - RenderTableCell* cell = current.cell; - - // Cells must always paint in the order in which they appear taking into account - // their upper left originating row/column. For cells with rowspans, avoid repainting - // if we've already seen the cell. - if (!cell || (r > startrow && (cellAt(r - 1, c).cell == cell))) - continue; - - RenderTableRow* row = toRenderTableRow(cell->parent()); - - if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) { - // We need to handle painting a stack of backgrounds. This stack (from bottom to top) consists of - // the column group, column, row group, row, and then the cell. - RenderObject* col = table()->colElement(c); - RenderObject* colGroup = 0; - if (col && col->parent()->style()->display() == TABLE_COLUMN_GROUP) - colGroup = col->parent(); - - // Column groups and columns first. - // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in - // the stack, since we have already opened a transparency layer (potentially) for the table row group. - // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the - // cell. - cell->paintBackgroundsBehindCell(paintInfo, tx, ty, colGroup); - cell->paintBackgroundsBehindCell(paintInfo, tx, ty, col); - - // Paint the row group next. - cell->paintBackgroundsBehindCell(paintInfo, tx, ty, this); - - // Paint the row next, but only if it doesn't have a layer. If a row has a layer, it will be responsible for - // painting the row background for the cell. - if (!row->hasSelfPaintingLayer()) - cell->paintBackgroundsBehindCell(paintInfo, tx, ty, row); + if (!m_hasMultipleCellLevels) { + // Draw the dirty cells in the order that they appear. + for (unsigned r = startrow; r < endrow; r++) { + for (unsigned c = startcol; c < endcol; c++) { + CellStruct& current = cellAt(r, c); + RenderTableCell* cell = current.primaryCell(); + if (!cell || (r > startrow && primaryCellAt(r - 1, c) == cell) || (c > startcol && primaryCellAt(r, c - 1) == cell)) + continue; + paintCell(cell, paintInfo, tx, ty); + } + } + } else { + // Draw the cells in the correct paint order. + Vector<RenderTableCell*> cells; + HashSet<RenderTableCell*> spanningCells; + for (unsigned r = startrow; r < endrow; r++) { + for (unsigned c = startcol; c < endcol; c++) { + CellStruct& current = cellAt(r, c); + if (!current.hasCells()) + continue; + for (unsigned i = 0; i < current.cells.size(); ++i) { + if (current.cells[i]->rowSpan() > 1 || current.cells[i]->colSpan() > 1) { + if (spanningCells.contains(current.cells[i])) + continue; + spanningCells.add(current.cells[i]); + } + cells.append(current.cells[i]); + } } - - if ((!cell->hasSelfPaintingLayer() && !row->hasSelfPaintingLayer()) || paintInfo.phase == PaintPhaseCollapsedTableBorders) - cell->paint(paintInfo, tx, ty); } + // Sort the dirty cells by paint order. + std::stable_sort(cells.begin(), cells.end(), compareCellPositions); + int size = cells.size(); + // Paint the cells. + for (int i = 0; i < size; ++i) + paintCell(cells[i], paintInfo, tx, ty); } } } @@ -1223,7 +1245,7 @@ int RenderTableSection::numColumns() const for (int r = 0; r < m_gridRows; ++r) { for (int c = result; c < table()->numEffCols(); ++c) { const CellStruct& cell = cellAt(r, c); - if (cell.cell || cell.inColSpan) + if (cell.hasCells() || cell.inColSpan) result = c; } } @@ -1233,24 +1255,29 @@ int RenderTableSection::numColumns() const void RenderTableSection::appendColumn(int pos) { - for (int row = 0; row < m_gridRows; ++row) { + for (int row = 0; row < m_gridRows; ++row) m_grid[row].row->resize(pos + 1); - CellStruct& c = cellAt(row, pos); - c.cell = 0; - c.inColSpan = false; - } } -void RenderTableSection::splitColumn(int pos, int newSize) +void RenderTableSection::splitColumn(int pos, int first) { if (m_cCol > pos) m_cCol++; for (int row = 0; row < m_gridRows; ++row) { - m_grid[row].row->resize(newSize); Row& r = *m_grid[row].row; - memmove(r.data() + pos + 1, r.data() + pos, (newSize - 1 - pos) * sizeof(CellStruct)); - r[pos + 1].cell = 0; - r[pos + 1].inColSpan = r[pos].inColSpan || r[pos].cell; + r.insert(pos + 1, CellStruct()); + if (r[pos].hasCells()) { + r[pos + 1].cells.append(r[pos].cells); + RenderTableCell* cell = r[pos].primaryCell(); + ASSERT(cell); + int colleft = cell->colSpan() - r[pos].inColSpan; + if (first > colleft) + r[pos + 1].inColSpan = 0; + else + r[pos + 1].inColSpan = first + r[pos].inColSpan; + } else { + r[pos + 1].inColSpan = 0; + } } } @@ -1279,7 +1306,6 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul return true; } } - return false; } diff --git a/WebCore/rendering/RenderTableSection.h b/WebCore/rendering/RenderTableSection.h index 9f6d5ea..6d2f752 100644 --- a/WebCore/rendering/RenderTableSection.h +++ b/WebCore/rendering/RenderTableSection.h @@ -54,8 +54,23 @@ public: RenderTable* table() const { return toRenderTable(parent()); } struct CellStruct { - RenderTableCell* cell; + Vector<RenderTableCell*, 1> cells; bool inColSpan; // true for columns after the first in a colspan + + CellStruct(): + inColSpan(false) {} + + RenderTableCell* primaryCell() + { + return hasCells() ? cells[cells.size() - 1] : 0; + } + + const RenderTableCell* primaryCell() const + { + return hasCells() ? cells[cells.size() - 1] : 0; + } + + bool hasCells() const { return cells.size() > 0; } }; typedef Vector<CellStruct> Row; @@ -69,9 +84,14 @@ public: CellStruct& cellAt(int row, int col) { return (*m_grid[row].row)[col]; } const CellStruct& cellAt(int row, int col) const { return (*m_grid[row].row)[col]; } + RenderTableCell* primaryCellAt(int row, int col) + { + CellStruct& c = (*m_grid[row].row)[col]; + return c.primaryCell(); + } void appendColumn(int pos); - void splitColumn(int pos, int newSize); + void splitColumn(int pos, int first); int calcOuterBorderTop() const; int calcOuterBorderBottom() const; @@ -121,6 +141,7 @@ private: virtual int leftmostPosition(bool includeOverflowInterior, bool includeSelf) const; virtual void paint(PaintInfo&, int tx, int ty); + virtual void paintCell(RenderTableCell*, PaintInfo&, int tx, int ty); virtual void paintObject(PaintInfo&, int tx, int ty); virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); @@ -150,6 +171,8 @@ private: bool m_needsCellRecalc; bool m_hasOverflowingCell; + + bool m_hasMultipleCellLevels; }; inline RenderTableSection* toRenderTableSection(RenderObject* object) diff --git a/WebCore/rendering/RenderText.cpp b/WebCore/rendering/RenderText.cpp index c70ac58..bd050d8 100644 --- a/WebCore/rendering/RenderText.cpp +++ b/WebCore/rendering/RenderText.cpp @@ -140,9 +140,8 @@ bool RenderText::isWordBreak() const void RenderText::updateNeedsTranscoding() { - const AtomicString& fontFamily = style()->font().family().family(); const TextEncoding* encoding = document()->decoder() ? &document()->decoder()->encoding() : 0; - m_needsTranscoding = fontTranscoder().needsTranscoding(fontFamily, encoding); + m_needsTranscoding = fontTranscoder().needsTranscoding(style()->font().fontDescription(), encoding); } void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) @@ -1044,9 +1043,8 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text) ASSERT(text); m_text = text; if (m_needsTranscoding) { - const AtomicString& fontFamily = style()->font().family().family(); const TextEncoding* encoding = document()->decoder() ? &document()->decoder()->encoding() : 0; - fontTranscoder().convert(m_text, fontFamily, encoding); + fontTranscoder().convert(m_text, style()->font().fontDescription(), encoding); } ASSERT(m_text); diff --git a/WebCore/rendering/RenderTextControlSingleLine.cpp b/WebCore/rendering/RenderTextControlSingleLine.cpp index 71d5a86..5b57513 100644 --- a/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -920,6 +920,11 @@ String RenderTextControlSingleLine::itemLabel(unsigned) const return String(); } +String RenderTextControlSingleLine::itemIcon(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 92ecadd..8c7e844 100644 --- a/WebCore/rendering/RenderTextControlSingleLine.h +++ b/WebCore/rendering/RenderTextControlSingleLine.h @@ -117,6 +117,7 @@ private: virtual void selectionCleared() {} virtual String itemText(unsigned listIndex) const; virtual String itemLabel(unsigned listIndex) const; + virtual String itemIcon(unsigned listIndex) const; virtual String itemToolTip(unsigned) const { return String(); } virtual String itemAccessibilityText(unsigned) const { return String(); } virtual bool itemIsEnabled(unsigned listIndex) const; diff --git a/WebCore/rendering/SVGResources.cpp b/WebCore/rendering/SVGResources.cpp new file mode 100644 index 0000000..de23ce1 --- /dev/null +++ b/WebCore/rendering/SVGResources.cpp @@ -0,0 +1,360 @@ +/* + Copyright (C) Research In Motion Limited 2010. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "SVGResources.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceClipper.h" +#include "RenderSVGResourceFilter.h" +#include "RenderSVGResourceMarker.h" +#include "RenderSVGResourceMasker.h" +#include "SVGPaint.h" +#include "SVGRenderStyle.h" +#include "SVGURIReference.h" + +namespace WebCore { + +SVGResources::SVGResources() + : m_clipper(0) +#if ENABLE(FILTERS) + , m_filter(0) +#endif + , m_markerStart(0) + , m_markerMid(0) + , m_markerEnd(0) + , m_masker(0) + , m_fill(0) + , m_stroke(0) +{ +} + +static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document* document, SVGPaint* paint, AtomicString& id, bool& hasPendingResource) +{ + ASSERT(paint); + + SVGPaint::SVGPaintType paintType = paint->paintType(); + if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) + return 0; + + id = SVGURIReference::getTarget(paint->uri()); + if (RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id)) + return container; + + hasPendingResource = true; + return 0; +} + +static inline void registerPendingResource(SVGDocumentExtensions* extensions, const AtomicString& id, Node* node) +{ + ASSERT(node); + if (!node->isSVGElement()) + return; + + SVGElement* svgElement = static_cast<SVGElement*>(node); + if (!svgElement->isStyled()) + return; + + extensions->addPendingResource(id, static_cast<SVGStyledElement*>(svgElement)); +} + +bool SVGResources::buildCachedResources(const RenderObject* object, const SVGRenderStyle* style) +{ + ASSERT(object); + ASSERT(style); + + Node* node = object->node(); + ASSERT(node); + + Document* document = object->document(); + ASSERT(document); + + SVGDocumentExtensions* extensions = document->accessSVGExtensions(); + ASSERT(extensions); + + bool foundResources = false; + if (style->hasClipper()) { + AtomicString id(style->clipperResource()); + m_clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(document, id); + if (m_clipper) + foundResources = true; + else + registerPendingResource(extensions, id, node); + } + + if (style->hasMasker()) { + AtomicString id(style->maskerResource()); + m_masker = getRenderSVGResourceById<RenderSVGResourceMasker>(document, id); + if (m_masker) + foundResources = true; + else + registerPendingResource(extensions, id, node); + } + +#if ENABLE(FILTERS) + if (style->hasFilter()) { + AtomicString id(style->filterResource()); + m_filter = getRenderSVGResourceById<RenderSVGResourceFilter>(document, id); + if (m_filter) + foundResources = true; + else + registerPendingResource(extensions, id, node); + } +#endif + + if (style->hasMarkers()) { + AtomicString markerStartId(style->markerStartResource()); + m_markerStart = getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerStartId); + if (m_markerStart) + foundResources = true; + else + registerPendingResource(extensions, markerStartId, node); + + AtomicString markerMidId(style->markerMidResource()); + m_markerMid = getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerMidId); + if (m_markerMid) + foundResources = true; + else + registerPendingResource(extensions, markerMidId, node); + + AtomicString markerEndId(style->markerEndResource()); + m_markerEnd = getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerEndId); + if (m_markerEnd) + foundResources = true; + else + registerPendingResource(extensions, markerEndId, node); + } + + if (style->hasFill()) { + bool hasPendingResource = false; + AtomicString id; + m_fill = paintingResourceFromSVGPaint(document, style->fillPaint(), id, hasPendingResource); + if (m_fill) + foundResources = true; + else if (hasPendingResource) + registerPendingResource(extensions, id, node); + } + + if (style->hasStroke()) { + bool hasPendingResource = false; + AtomicString id; + m_stroke = paintingResourceFromSVGPaint(document, style->strokePaint(), id, hasPendingResource); + if (m_stroke) + foundResources = true; + else if (hasPendingResource) + registerPendingResource(extensions, id, node); + } + + return foundResources; +} + +void SVGResources::invalidateClient(RenderObject* object) const +{ + // Ordinary resources + if (m_clipper) + m_clipper->invalidateClient(object); +#if ENABLE(FILTERS) + if (m_filter) + m_filter->invalidateClient(object); +#endif + if (m_masker) + m_masker->invalidateClient(object); + if (m_markerStart) + m_markerStart->invalidateClient(object); + if (m_markerMid) + m_markerMid->invalidateClient(object); + if (m_markerEnd) + m_markerEnd->invalidateClient(object); + + // Paint servers + if (m_fill) + m_fill->invalidateClient(object); + if (m_stroke) + m_stroke->invalidateClient(object); +} + +void SVGResources::resourceDestroyed(RenderSVGResourceContainer* resource) +{ + ASSERT(resource); + + switch (resource->resourceType()) { + case MaskerResourceType: + if (m_masker == resource) { + m_masker->invalidateClients(); + m_masker = 0; + } + break; + case MarkerResourceType: + if (m_markerStart == resource) { + m_markerStart->invalidateClients(); + m_markerStart = 0; + } + + if (m_markerMid == resource) { + m_markerMid->invalidateClients(); + m_markerMid = 0; + } + + if (m_markerEnd == resource) { + m_markerEnd->invalidateClients(); + m_markerEnd = 0; + } + break; + case PatternResourceType: + case LinearGradientResourceType: + case RadialGradientResourceType: + if (m_fill == resource) { + m_fill->invalidateClients(); + m_fill = 0; + } + + if (m_stroke == resource) { + m_stroke->invalidateClients(); + m_stroke = 0; + } + break; +#if ENABLE(FILTERS) + case FilterResourceType: + if (m_filter == resource) { + m_filter->invalidateClients(); + m_filter = 0; + } + break; +#endif + case ClipperResourceType: + if (m_clipper == resource) { + m_clipper->invalidateClients(); + m_clipper = 0; + } + break; + case SolidColorResourceType: + ASSERT_NOT_REACHED(); + } +} + +void SVGResources::buildSetOfResources(HashSet<RenderSVGResourceContainer*>& set) +{ + // Ordinary resources + if (m_clipper) + set.add(m_clipper); +#if ENABLE(FILTERS) + if (m_filter) + set.add(m_filter); +#endif + if (m_markerStart) + set.add(m_markerStart); + if (m_markerMid) + set.add(m_markerMid); + if (m_markerEnd) + set.add(m_markerEnd); + if (m_masker) + set.add(m_masker); + + // Paint servers + if (m_fill) + set.add(m_fill); + if (m_stroke) + set.add(m_stroke); +} + +void SVGResources::resetClipper() +{ + ASSERT(m_clipper); + m_clipper = 0; +} + +#if ENABLE(FILTERS) +void SVGResources::resetFilter() +{ + ASSERT(m_filter); + m_filter = 0; +} +#endif + +void SVGResources::resetMarkerStart() +{ + ASSERT(m_markerStart); + m_markerStart = 0; +} + +void SVGResources::resetMarkerMid() +{ + ASSERT(m_markerMid); + m_markerMid = 0; +} + +void SVGResources::resetMarkerEnd() +{ + ASSERT(m_markerEnd); + m_markerEnd = 0; +} + +void SVGResources::resetMasker() +{ + ASSERT(m_masker); + m_masker = 0; +} + +void SVGResources::resetFill() +{ + ASSERT(m_fill); + m_fill = 0; +} + +void SVGResources::resetStroke() +{ + ASSERT(m_stroke); + m_stroke = 0; +} + +#ifndef NDEBUG +void SVGResources::dump(const RenderObject* object) +{ + ASSERT(object); + ASSERT(object->node()); + + fprintf(stderr, "-> this=%p, SVGResources(renderer=%p, node=%p)\n", this, object, object->node()); + fprintf(stderr, " | DOM Tree:\n"); + object->node()->showTreeForThis(); + + fprintf(stderr, "\n | List of resources:\n"); + if (m_clipper) + fprintf(stderr, " |-> Clipper : %p (node=%p)\n", m_clipper, m_clipper->node()); +#if ENABLE(FILTERS) + if (m_filter) + fprintf(stderr, " |-> Filter : %p (node=%p)\n", m_filter, m_filter->node()); +#endif + if (m_markerStart) + fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", m_markerStart, m_markerStart->node()); + if (m_markerMid) + fprintf(stderr, " |-> MarkerMid : %p (node=%p)\n", m_markerMid, m_markerMid->node()); + if (m_markerEnd) + fprintf(stderr, " |-> MarkerEnd : %p (node=%p)\n", m_markerEnd, m_markerEnd->node()); + if (m_masker) + fprintf(stderr, " |-> Masker : %p (node=%p)\n", m_masker, m_masker->node()); + if (m_fill) + fprintf(stderr, " |-> Fill : %p (node=%p)\n", m_fill, m_fill->node()); + if (m_stroke) + fprintf(stderr, " |-> Stroke : %p (node=%p)\n", m_stroke, m_stroke->node()); +} +#endif + +} + +#endif diff --git a/WebCore/rendering/SVGResources.h b/WebCore/rendering/SVGResources.h new file mode 100644 index 0000000..57a4140 --- /dev/null +++ b/WebCore/rendering/SVGResources.h @@ -0,0 +1,103 @@ +/* + Copyright (C) Research In Motion Limited 2010. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SVGResources_h +#define SVGResources_h + +#if ENABLE(SVG) +#include <wtf/HashSet.h> +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class Document; +class RenderObject; +class RenderSVGResourceClipper; +class RenderSVGResourceContainer; +class RenderSVGResourceFilter; +class RenderSVGResourceMarker; +class RenderSVGResourceMasker; +class SVGRenderStyle; + +// Holds a set of resources associated with a RenderObject +class SVGResources { +public: + SVGResources(); + + bool buildCachedResources(const RenderObject*, const SVGRenderStyle*); + + // Ordinary resources + RenderSVGResourceClipper* clipper() const { return m_clipper; } +#if ENABLE(FILTERS) + RenderSVGResourceFilter* filter() const { return m_filter; } +#endif + RenderSVGResourceMarker* markerStart() const { return m_markerStart; } + RenderSVGResourceMarker* markerMid() const { return m_markerMid; } + RenderSVGResourceMarker* markerEnd() const { return m_markerEnd; } + RenderSVGResourceMasker* masker() const { return m_masker; } + + // Paint servers + RenderSVGResourceContainer* fill() const { return m_fill; } + RenderSVGResourceContainer* stroke() const { return m_stroke; } + + void buildSetOfResources(HashSet<RenderSVGResourceContainer*>&); + + // Methods operating on all cached resources + void invalidateClient(RenderObject*) const; + void resourceDestroyed(RenderSVGResourceContainer*); + +#ifndef NDEBUG + void dump(const RenderObject*); +#endif + +private: + friend class SVGResourcesCycleSolver; + + // Only used by SVGResourcesCache cycle detection logic + void resetClipper(); +#if ENABLE(FILTERS) + void resetFilter(); +#endif + void resetMarkerStart(); + void resetMarkerMid(); + void resetMarkerEnd(); + void resetMasker(); + void resetFill(); + void resetStroke(); + +private: + // Ordinary resources + RenderSVGResourceClipper* m_clipper; +#if ENABLE(FILTERS) + RenderSVGResourceFilter* m_filter; +#endif + RenderSVGResourceMarker* m_markerStart; + RenderSVGResourceMarker* m_markerMid; + RenderSVGResourceMarker* m_markerEnd; + RenderSVGResourceMasker* m_masker; + + // Paint servers + RenderSVGResourceContainer* m_fill; + RenderSVGResourceContainer* m_stroke; +}; + +} + +#endif +#endif diff --git a/WebCore/rendering/SVGResourcesCache.cpp b/WebCore/rendering/SVGResourcesCache.cpp new file mode 100644 index 0000000..46586cc --- /dev/null +++ b/WebCore/rendering/SVGResourcesCache.cpp @@ -0,0 +1,179 @@ +/* + Copyright (C) Research In Motion Limited 2010. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "SVGResourcesCache.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceContainer.h" +#include "SVGDocumentExtensions.h" +#include "SVGResources.h" +#include "SVGResourcesCycleSolver.h" + +namespace WebCore { + +SVGResourcesCache::SVGResourcesCache() +{ +} + +SVGResourcesCache::~SVGResourcesCache() +{ + if (m_cache.isEmpty()) + return; + + deleteAllValues(m_cache); + m_cache.clear(); +} + +void SVGResourcesCache::addResourcesFromRenderObject(RenderObject* object, const RenderStyle* style) +{ + ASSERT(object); + ASSERT(style); + ASSERT(!m_cache.contains(object)); + + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + + // Build a list of all resources associated with the passed RenderObject + SVGResources* resources = new SVGResources; + if (!resources->buildCachedResources(object, svgStyle)) { + delete resources; + return; + } + + // Put object in cache. + m_cache.set(object, resources); + + // Run cycle-detection _afterwards_, so self-references can be caught as well. + SVGResourcesCycleSolver solver(object, resources); + solver.resolveCycles(); + + // Walk resources and register the render object at each resources. + HashSet<RenderSVGResourceContainer*> resourceSet; + resources->buildSetOfResources(resourceSet); + + HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it) + (*it)->addClient(object); +} + +void SVGResourcesCache::removeResourcesFromRenderObject(RenderObject* object) +{ + if (!m_cache.contains(object)) + return; + + SVGResources* resources = m_cache.get(object); + + // Walk resources and register the render object at each resources. + HashSet<RenderSVGResourceContainer*> resourceSet; + resources->buildSetOfResources(resourceSet); + + HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it) + (*it)->removeClient(object); + + delete m_cache.take(object); +} + +static inline SVGResourcesCache* resourcesCacheFromRenderObject(RenderObject* renderer) +{ + Document* document = renderer->document(); + ASSERT(document); + + SVGDocumentExtensions* extensions = document->accessSVGExtensions(); + ASSERT(extensions); + + SVGResourcesCache* cache = extensions->resourcesCache(); + ASSERT(cache); + + return cache; +} + +SVGResources* SVGResourcesCache::cachedResourcesForRenderObject(RenderObject* renderer) +{ + ASSERT(renderer); + SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); + if (!cache->m_cache.contains(renderer)) + return 0; + + return cache->m_cache.get(renderer); +} + +void SVGResourcesCache::clientLayoutChanged(RenderObject* object) +{ + SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); + if (!resources) + return; + + resources->invalidateClient(object); +} + +void SVGResourcesCache::clientStyleChanged(RenderObject* renderer, StyleDifference diff, const RenderStyle* newStyle) +{ + ASSERT(renderer); + if (diff == StyleDifferenceEqual) + return; + + clientUpdatedFromElement(renderer, newStyle); + + // Invalidate resources in ancestor chain, if needed. + RenderObject* parent = renderer->parent(); + while (parent) { + if (parent->isSVGResourceContainer()) { + parent->toRenderSVGResourceContainer()->invalidateClients(); + break; + } + + parent = parent->parent(); + } +} + +void SVGResourcesCache::clientUpdatedFromElement(RenderObject* renderer, const RenderStyle* newStyle) +{ + ASSERT(renderer); + ASSERT(renderer->parent()); + + SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); + cache->removeResourcesFromRenderObject(renderer); + cache->addResourcesFromRenderObject(renderer, newStyle); +} + +void SVGResourcesCache::clientDestroyed(RenderObject* renderer) +{ + ASSERT(renderer); + SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); + cache->removeResourcesFromRenderObject(renderer); +} + +void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer* resource) +{ + ASSERT(resource); + SVGResourcesCache* cache = resourcesCacheFromRenderObject(resource); + + // The resource itself may have clients, that need to be notified. + cache->removeResourcesFromRenderObject(resource); + + HashMap<RenderObject*, SVGResources*>::iterator end = cache->m_cache.end(); + for (HashMap<RenderObject*, SVGResources*>::iterator it = cache->m_cache.begin(); it != end; ++it) + it->second->resourceDestroyed(resource); +} + +} + +#endif diff --git a/WebCore/rendering/SVGResourcesCache.h b/WebCore/rendering/SVGResourcesCache.h new file mode 100644 index 0000000..4a61570 --- /dev/null +++ b/WebCore/rendering/SVGResourcesCache.h @@ -0,0 +1,65 @@ +/* + Copyright (C) Research In Motion Limited 2010. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SVGResourcesCache_h +#define SVGResourcesCache_h + +#if ENABLE(SVG) +#include "RenderStyleConstants.h" +#include <wtf/HashMap.h> + +namespace WebCore { + +class RenderObject; +class RenderStyle; +class RenderSVGResourceContainer; +class SVGResources; + +class SVGResourcesCache : public Noncopyable { +public: + SVGResourcesCache(); + ~SVGResourcesCache(); + + void addResourcesFromRenderObject(RenderObject*, const RenderStyle*); + void removeResourcesFromRenderObject(RenderObject*); + static SVGResources* cachedResourcesForRenderObject(RenderObject*); + + // Called from all SVG renderers destroy() methods - except for RenderSVGResourceContainer. + static void clientDestroyed(RenderObject*); + + // Called from all SVG renderers layout() methods. + static void clientLayoutChanged(RenderObject*); + + // Called from all SVG renderers styleDidChange() methods. + static void clientStyleChanged(RenderObject*, StyleDifference, const RenderStyle* newStyle); + + // Called from all SVG renderers updateFromElement() methods. + static void clientUpdatedFromElement(RenderObject*, const RenderStyle* newStyle); + + // Called from RenderSVGResourceContainer::destroy(). + static void resourceDestroyed(RenderSVGResourceContainer*); + +private: + HashMap<RenderObject*, SVGResources*> m_cache; +}; + +} + +#endif +#endif diff --git a/WebCore/rendering/SVGResourcesCycleSolver.cpp b/WebCore/rendering/SVGResourcesCycleSolver.cpp new file mode 100644 index 0000000..206efe5 --- /dev/null +++ b/WebCore/rendering/SVGResourcesCycleSolver.cpp @@ -0,0 +1,303 @@ +/* + Copyright (C) Research In Motion Limited 2010. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "SVGResourcesCycleSolver.h" + +// Set to a value > 0, to debug the resource cache. +#define DEBUG_CYCLE_DETECTION 0 + +#if ENABLE(SVG) +#include "RenderSVGResourceClipper.h" +#include "RenderSVGResourceFilter.h" +#include "RenderSVGResourceMarker.h" +#include "RenderSVGResourceMasker.h" +#include "SVGFilterElement.h" +#include "SVGGradientElement.h" +#include "SVGPatternElement.h" +#include "SVGResources.h" +#include "SVGResourcesCache.h" + +namespace WebCore { + +SVGResourcesCycleSolver::SVGResourcesCycleSolver(RenderObject* renderer, SVGResources* resources) + : m_renderer(renderer) + , m_resources(resources) +{ + ASSERT(m_renderer); + ASSERT(m_resources); +} + +SVGResourcesCycleSolver::~SVGResourcesCycleSolver() +{ +} + +bool SVGResourcesCycleSolver::resourceContainsCycles(RenderObject* renderer) const +{ + ASSERT(renderer); + + // First operate on the resources of the given renderer. + // <marker id="a"> <path marker-start="url(#b)"/> ... + // <marker id="b" marker-start="url(#a)"/> + if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer)) { + HashSet<RenderSVGResourceContainer*> resourceSet; + resources->buildSetOfResources(resourceSet); + + // Walk all resources and check wheter they reference any resource contained in the resources set. + HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it) { + if (m_allResources.contains(*it)) + return true; + } + } + + // Then operate on the child resources of the given renderer. + // <marker id="a"> <path marker-start="url(#b)"/> ... + // <marker id="b"> <path marker-start="url(#a)"/> ... + for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) { + SVGResources* childResources = SVGResourcesCache::cachedResourcesForRenderObject(child); + if (!childResources) + continue; + + // A child of the given 'resource' contains resources. + HashSet<RenderSVGResourceContainer*> childSet; + childResources->buildSetOfResources(childSet); + + // Walk all child resources and check wheter they reference any resource contained in the resources set. + HashSet<RenderSVGResourceContainer*>::iterator end = childSet.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = childSet.begin(); it != end; ++it) { + if (m_allResources.contains(*it)) + return true; + } + + // Walk children recursively, stop immediately if we found a cycle + if (resourceContainsCycles(child)) + return true; + } + + return false; +} + +static inline String targetReferenceFromResource(SVGElement* element, bool& isValid) +{ + String target; + if (element->hasTagName(SVGNames::patternTag)) + target = static_cast<SVGPatternElement*>(element)->href(); + else if (element->hasTagName(SVGNames::linearGradientTag) || element->hasTagName(SVGNames::radialGradientTag)) + target = static_cast<SVGGradientElement*>(element)->href(); +// ANDROID +// This is deleted upstream so we cannot upstream the guard +// http://trac.webkit.org/changeset/64440/trunk/WebCore/rendering/SVGResourcesCycleSolver.cpp +#if ENABLE(FILTERS) + else if (element->hasTagName(SVGNames::filterTag)) + target = static_cast<SVGFilterElement*>(element)->href(); +#endif + else { + isValid = false; + return target; + } + + return SVGURIReference::getTarget(target); +} + +static inline void setFollowLinkForChainableResource(SVGElement*, bool) +{ + // FIXME: Enable once the follow-up patch for bug 43031 lands +} + +bool SVGResourcesCycleSolver::chainableResourceContainsCycles(RenderSVGResourceContainer* container) const +{ + ASSERT(container); + ASSERT(container->node()); + ASSERT(container->node()->isSVGElement()); + + // Chainable resources cycle detection is performed in the DOM tree. + SVGElement* element = static_cast<SVGElement*>(container->node()); + ASSERT(element); + + HashSet<SVGElement*> processedObjects; + + bool isValid = true; + String target = targetReferenceFromResource(element, isValid); + ASSERT(isValid); + + SVGElement* previousElement = element; + while (!target.isEmpty()) { + Node* targetNode = element->document()->getElementById(target); + if (!targetNode || !targetNode->isSVGElement()) + break; + + // Catch cylic chaining, otherwhise we'll run into an infinite loop here. + // <pattern id="foo" xlink:href="#bar"/> <pattern id="bar xlink:href="#foo"/> + SVGElement* targetElement = static_cast<SVGElement*>(targetNode); + + bool followLink = true; + if (processedObjects.contains(targetElement) || targetElement == element) + followLink = false; + + setFollowLinkForChainableResource(previousElement, followLink); + if (!followLink) + return false; + + previousElement = targetElement; + processedObjects.add(targetElement); + target = targetReferenceFromResource(targetElement, isValid); + if (!isValid) + break; + } + + // Couldn't find any direct cycle in the xlink:href chain, maybe there's an indirect one. + // <pattern id="foo" xlink:href="#bar"/> <pattern id="bar"> <rect fill="url(#foo)"... + HashSet<SVGElement*>::iterator end = processedObjects.end(); + for (HashSet<SVGElement*>::iterator it = processedObjects.begin(); it != end; ++it) { + RenderObject* renderer = (*it)->renderer(); + if (!renderer) + continue; + ASSERT(renderer->isSVGResourceContainer()); + if (m_allResources.contains(renderer->toRenderSVGResourceContainer())) + return true; + } + + return false; +} + +void SVGResourcesCycleSolver::resolveCycles() +{ + ASSERT(m_allResources.isEmpty()); + +#if DEBUG_CYCLE_DETECTION > 0 + fprintf(stderr, "\nBefore cycle detection:\n"); + m_resources->dump(m_renderer); +#endif + + // Stash all resources into a HashSet for the ease of traversing. + HashSet<RenderSVGResourceContainer*> localResources; + m_resources->buildSetOfResources(localResources); + ASSERT(!localResources.isEmpty()); + + // Add all parent resource containers to the HashSet. + HashSet<RenderSVGResourceContainer*> parentResources; + RenderObject* parent = m_renderer->parent(); + while (parent) { + if (parent->isSVGResourceContainer()) + parentResources.add(parent->toRenderSVGResourceContainer()); + parent = parent->parent(); + } + +#if DEBUG_CYCLE_DETECTION > 0 + fprintf(stderr, "\nDetecting wheter any resources references any of following objects:\n"); + { + fprintf(stderr, "Local resources:\n"); + HashSet<RenderSVGResourceContainer*>::iterator end = localResources.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) + fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node()); + + fprintf(stderr, "Parent resources:\n"); + end = parentResources.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it) + fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node()); + } +#endif + + // Build combined set of local and parent resources. + m_allResources = localResources; + HashSet<RenderSVGResourceContainer*>::iterator end = parentResources.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it) + m_allResources.add(*it); + + ASSERT(!m_allResources.isEmpty()); + + // The job of this function is to determine wheter any of the 'resources' associated with the given 'renderer' + // references us (or wheter any of its kids references us) -> that's a cycle, we need to find and break it. + end = localResources.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) { + RenderSVGResourceContainer* resource = *it; + + // Special handling for resources that can be chained using xlink:href - need to detect cycles as well! + switch (resource->resourceType()) { + case PatternResourceType: + case LinearGradientResourceType: + case RadialGradientResourceType: + case FilterResourceType: + if (chainableResourceContainsCycles(resource)) { + breakCycle(resource); + continue; + } + break; + default: + break; + } + + if (parentResources.contains(resource) || resourceContainsCycles(resource)) + breakCycle(resource); + } + +#if DEBUG_CYCLE_DETECTION > 0 + fprintf(stderr, "\nAfter cycle detection:\n"); + m_resources->dump(m_renderer); +#endif + + m_allResources.clear(); +} + +void SVGResourcesCycleSolver::breakCycle(RenderSVGResourceContainer* resourceLeadingToCycle) +{ + ASSERT(resourceLeadingToCycle); + switch (resourceLeadingToCycle->resourceType()) { + case MaskerResourceType: + ASSERT(resourceLeadingToCycle == m_resources->masker()); + m_resources->resetMasker(); + break; + case MarkerResourceType: + ASSERT(resourceLeadingToCycle == m_resources->markerStart() || resourceLeadingToCycle == m_resources->markerMid() || resourceLeadingToCycle == m_resources->markerEnd()); + if (m_resources->markerStart() == resourceLeadingToCycle) + m_resources->resetMarkerStart(); + if (m_resources->markerMid() == resourceLeadingToCycle) + m_resources->resetMarkerMid(); + if (m_resources->markerEnd() == resourceLeadingToCycle) + m_resources->resetMarkerEnd(); + break; + case PatternResourceType: + case LinearGradientResourceType: + case RadialGradientResourceType: + ASSERT(resourceLeadingToCycle == m_resources->fill() || resourceLeadingToCycle == m_resources->stroke()); + if (m_resources->fill() == resourceLeadingToCycle) + m_resources->resetFill(); + if (m_resources->stroke() == resourceLeadingToCycle) + m_resources->resetStroke(); + break; + case FilterResourceType: + ASSERT(resourceLeadingToCycle == m_resources->filter()); +#if ENABLE(FILTERS) + m_resources->resetFilter(); +#endif + break; + case ClipperResourceType: + ASSERT(resourceLeadingToCycle == m_resources->clipper()); + m_resources->resetClipper(); + break; + case SolidColorResourceType: + ASSERT_NOT_REACHED(); + break; + } +} + +} + +#endif diff --git a/WebCore/rendering/SVGResourcesCycleSolver.h b/WebCore/rendering/SVGResourcesCycleSolver.h new file mode 100644 index 0000000..1f49354 --- /dev/null +++ b/WebCore/rendering/SVGResourcesCycleSolver.h @@ -0,0 +1,52 @@ +/* + Copyright (C) Research In Motion Limited 2010. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SVGResourcesCycleSolver_h +#define SVGResourcesCycleSolver_h + +#if ENABLE(SVG) +#include <wtf/HashSet.h> + +namespace WebCore { + +class RenderObject; +class RenderSVGResourceContainer; +class SVGResources; + +class SVGResourcesCycleSolver : public Noncopyable { +public: + SVGResourcesCycleSolver(RenderObject*, SVGResources*); + ~SVGResourcesCycleSolver(); + + void resolveCycles(); + +private: + bool resourceContainsCycles(RenderObject*) const; + bool chainableResourceContainsCycles(RenderSVGResourceContainer*) const; + void breakCycle(RenderSVGResourceContainer*); + + RenderObject* m_renderer; + SVGResources* m_resources; + HashSet<RenderSVGResourceContainer*> m_allResources; +}; + +} + +#endif +#endif diff --git a/WebCore/rendering/TextControlInnerElements.cpp b/WebCore/rendering/TextControlInnerElements.cpp index 24e1d74..b29876a 100644 --- a/WebCore/rendering/TextControlInnerElements.cpp +++ b/WebCore/rendering/TextControlInnerElements.cpp @@ -232,7 +232,13 @@ void SearchFieldCancelButtonElement::defaultEventHandler(Event* event) m_capturing = false; } if (hovered()) { + RefPtr<HTMLInputElement> protector(input); + String oldValue = input->value(); input->setValue(""); + if (!oldValue.isEmpty()) { + toRenderTextControl(input->renderer())->setChangedSinceLastChangeEvent(true); + input->dispatchEvent(Event::create(eventNames().inputEvent, true, false)); + } input->onSearch(); event->setDefaultHandled(); } @@ -374,7 +380,7 @@ void InputFieldSpeechButtonElement::defaultEventHandler(Event* event) m_capturing = false; } if (hovered()) { - speechInput()->startRecognition(); + speechInput()->startRecognition(this); event->setDefaultHandled(); } } @@ -386,17 +392,20 @@ void InputFieldSpeechButtonElement::defaultEventHandler(Event* event) SpeechInput* InputFieldSpeechButtonElement::speechInput() { - if (!m_speechInput) - m_speechInput.set(new SpeechInput(document()->page()->speechInputClient(), this)); - return m_speechInput.get(); + return document()->page()->speechInput(); } -void InputFieldSpeechButtonElement::recordingComplete() +void InputFieldSpeechButtonElement::didCompleteRecording() { // FIXME: Add UI feedback here to indicate that audio recording stopped and recognition is // in progress. } +void InputFieldSpeechButtonElement::didCompleteRecognition() +{ + // FIXME: Add UI feedback here to indicate that audio recognition has ended. +} + void InputFieldSpeechButtonElement::setRecognitionResult(const String& result) { HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); diff --git a/WebCore/rendering/TextControlInnerElements.h b/WebCore/rendering/TextControlInnerElements.h index 68d6ff4..ed38221 100644 --- a/WebCore/rendering/TextControlInnerElements.h +++ b/WebCore/rendering/TextControlInnerElements.h @@ -124,7 +124,8 @@ public: virtual void defaultEventHandler(Event*); // SpeechInputListener methods. - void recordingComplete(); + void didCompleteRecording(); + void didCompleteRecognition(); void setRecognitionResult(const String& result); private: @@ -133,7 +134,6 @@ private: SpeechInput* speechInput(); bool m_capturing; - OwnPtr<SpeechInput> m_speechInput; }; #endif // ENABLE(INPUT_SPEECH) diff --git a/WebCore/rendering/break_lines.cpp b/WebCore/rendering/break_lines.cpp index 4b6c0aa..054cd43 100644 --- a/WebCore/rendering/break_lines.cpp +++ b/WebCore/rendering/break_lines.cpp @@ -38,60 +38,115 @@ namespace WebCore { static inline bool isBreakableSpace(UChar ch, bool treatNoBreakSpaceAsBreak) { switch (ch) { - case ' ': - case '\n': - case '\t': - return true; - case noBreakSpace: - return treatNoBreakSpaceAsBreak; - default: - return false; + case ' ': + case '\n': + case '\t': + return true; + case noBreakSpace: + return treatNoBreakSpaceAsBreak; + default: + return false; } } -// This differs from the Unicode algorithm only in that Unicode does not break -// between a question mark and a vertical line (U+007C). -static const unsigned char internetExplorerLineBreaksAfterQuestionMarkTable[0x80] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, // \t - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, // ! " ' ) , . / - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, // : ; ? - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, // ] - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 // } +static const UChar asciiLineBreakTableFirstChar = '!'; +static const UChar asciiLineBreakTableLastChar = 127; + +// Pack 8 bits into one byte +#define B(a, b, c, d, e, f, g, h) \ + ((a) | ((b) << 1) | ((c) << 2) | ((d) << 3) | ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7)) + +// Line breaking table row for each digit (0-9) +#define DI { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + +// Line breaking table row for ascii letters (a-z A-Z) +#define AL { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + +#define F 0xFF + +// Line breaking table for printable ASCII characters. Line breaking opportunities in this table are as below: +// - before openning punctuations such as '(', '<', '[', '{' after certain characters (compatible with Firefox 3.6); +// - after '-' and '?' (backward-compatible, and compatible with Internet Explorer). +// Please refer to <https://bugs.webkit.org/show_bug.cgi?id=37698> for line breaking matrixes of different browsers +// and the ICU standard. +static const unsigned char asciiLineBreakTable[][(asciiLineBreakTableLastChar - asciiLineBreakTableFirstChar) / 8 + 1] = { + // ! " # $ % & ' ( ) * + , - . / 0 1-8 9 : ; < = > ? @ A-X Y Z [ \ ] ^ _ ` a-x y z { | } ~ DEL + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // ! + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // " + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // # + { B(0, 0, 0, 0, 0, 0, 0, 0), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0) }, // $ + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // % + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // & + { B(0, 0, 0, 0, 0, 0, 0, 0), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0) }, // ' + { B(0, 0, 0, 0, 0, 0, 0, 0), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0) }, // ( + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // ) + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // * + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // + + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // , + { B(1, 1, 1, 1, 1, 1, 1, 1), B(1, 1, 1, 1, 1, 1, 1, 1), F, B(1, 1, 1, 1, 1, 1, 1, 1), F, F, F, B(1, 1, 1, 1, 1, 1, 1, 1), F, F, F, B(1, 1, 1, 1, 1, 1, 1, 1) }, // - + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // . + { B(0, 0, 0, 0, 0, 0, 0, 0), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0) }, // / + DI, DI, DI, DI, DI, DI, DI, DI, DI, DI, // 0-9 + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // : + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // ; + { B(0, 0, 0, 0, 0, 0, 0, 0), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0) }, // < + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // = + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // > + { B(0, 0, 1, 1, 1, 1, 0, 1), B(0, 1, 1, 0, 1, 0, 0, 1), F, B(1, 0, 0, 1, 1, 1, 0, 1), F, F, F, B(1, 1, 1, 1, 0, 1, 1, 1), F, F, F, B(1, 1, 1, 1, 0, 1, 1, 0) }, // ? + { B(0, 0, 0, 0, 0, 0, 0, 0), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0) }, // @ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, // A-Z + { B(0, 0, 0, 0, 0, 0, 0, 0), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0) }, // [ + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // '\' + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // ] + { B(0, 0, 0, 0, 0, 0, 0, 0), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0) }, // ^ + { B(0, 0, 0, 0, 0, 0, 0, 0), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0) }, // _ + { B(0, 0, 0, 0, 0, 0, 0, 0), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0) }, // ` + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, // a-z + { B(0, 0, 0, 0, 0, 0, 0, 0), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0) }, // { + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // | + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // } + { B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // ~ + { B(0, 0, 0, 0, 0, 0, 0, 0), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 0, 0, 0, 0, 0, 0) }, // DEL }; -static const size_t internetExplorerLineBreaksAfterQuestionMarkTableSize = sizeof(internetExplorerLineBreaksAfterQuestionMarkTable) / sizeof(*internetExplorerLineBreaksAfterQuestionMarkTable); +#undef B +#undef F +#undef DI +#undef AL + +COMPILE_ASSERT(sizeof(asciiLineBreakTable) / sizeof(asciiLineBreakTable[0]) == asciiLineBreakTableLastChar - asciiLineBreakTableFirstChar + 1, + TestLineBreakTableConsistency); static inline bool shouldBreakAfter(UChar ch, UChar nextCh) { switch (ch) { - // For a question mark preceding a non-ASCII characters, defer to the Unicode algorithm by returning false. - // For ASCII characters, use a lookup table for enhanced speed and for compatibility with Internet Explorer. - case '?': - return nextCh < internetExplorerLineBreaksAfterQuestionMarkTableSize && internetExplorerLineBreaksAfterQuestionMarkTable[nextCh]; - // Internet Explorer always allows breaking after a hyphen. - case '-': - case softHyphen: + case ideographicComma: + case ideographicFullStop: // FIXME: cases for ideographicComma and ideographicFullStop are a workaround for an issue in Unicode 5.0 // which is likely to be resolved in Unicode 5.1 <http://bugs.webkit.org/show_bug.cgi?id=17411>. // We may want to remove or conditionalize this workaround at some point. - case ideographicComma: - case ideographicFullStop: #ifdef ANDROID_LAYOUT // as '/' is used in uri which is always long, we would like to break it - case '/': + case '/': #endif - return true; - default: - return false; + return true; + default: + // If both ch and nextCh are ASCII characters, use a lookup table for enhanced speed and for compatibility + // with other browsers (see comments for asciiLineBreakTable for details). + if (ch >= asciiLineBreakTableFirstChar && ch <= asciiLineBreakTableLastChar + && nextCh >= asciiLineBreakTableFirstChar && nextCh <= asciiLineBreakTableLastChar) { + const unsigned char* tableRow = asciiLineBreakTable[ch - asciiLineBreakTableFirstChar]; + int nextChIndex = nextCh - asciiLineBreakTableFirstChar; + return tableRow[nextChIndex / 8] & (1 << (nextChIndex % 8)); + } + // Otherwise defer to the Unicode algorithm by returning false. + return false; } } static inline bool needsLineBreakIterator(UChar ch) { - return ch > 0x7F && ch != noBreakSpace; + return ch > asciiLineBreakTableLastChar && ch != noBreakSpace; } #if PLATFORM(MAC) && defined(BUILDING_ON_TIGER) |
