summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/rendering')
-rw-r--r--WebCore/rendering/AutoTableLayout.cpp6
-rw-r--r--WebCore/rendering/HitTestRequest.h6
-rw-r--r--WebCore/rendering/RenderBox.cpp8
-rw-r--r--WebCore/rendering/RenderBoxModelObject.cpp38
-rw-r--r--WebCore/rendering/RenderBoxModelObject.h2
-rw-r--r--WebCore/rendering/RenderInline.h4
-rw-r--r--WebCore/rendering/RenderLayer.cpp28
-rw-r--r--WebCore/rendering/RenderLayerBacking.cpp65
-rw-r--r--WebCore/rendering/RenderLayerCompositor.cpp67
-rw-r--r--WebCore/rendering/RenderLayerCompositor.h6
-rw-r--r--WebCore/rendering/RenderMediaControlsChromium.cpp2
-rw-r--r--WebCore/rendering/RenderMenuList.cpp5
-rw-r--r--WebCore/rendering/RenderMenuList.h1
-rw-r--r--WebCore/rendering/RenderSVGAllInOne.cpp4
-rw-r--r--WebCore/rendering/RenderSVGHiddenContainer.h5
-rw-r--r--WebCore/rendering/RenderSVGResourceContainer.cpp131
-rw-r--r--WebCore/rendering/RenderSVGResourceContainer.h110
-rw-r--r--WebCore/rendering/RenderTable.cpp42
-rw-r--r--WebCore/rendering/RenderTableSection.cpp274
-rw-r--r--WebCore/rendering/RenderTableSection.h27
-rw-r--r--WebCore/rendering/RenderText.cpp6
-rw-r--r--WebCore/rendering/RenderTextControlSingleLine.cpp5
-rw-r--r--WebCore/rendering/RenderTextControlSingleLine.h1
-rw-r--r--WebCore/rendering/SVGResources.cpp360
-rw-r--r--WebCore/rendering/SVGResources.h103
-rw-r--r--WebCore/rendering/SVGResourcesCache.cpp179
-rw-r--r--WebCore/rendering/SVGResourcesCache.h65
-rw-r--r--WebCore/rendering/SVGResourcesCycleSolver.cpp303
-rw-r--r--WebCore/rendering/SVGResourcesCycleSolver.h52
-rw-r--r--WebCore/rendering/TextControlInnerElements.cpp19
-rw-r--r--WebCore/rendering/TextControlInnerElements.h4
-rw-r--r--WebCore/rendering/break_lines.cpp123
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)