diff options
| author | Simon Hausmann <simon.hausmann@digia.com> | 2012-11-22 09:09:45 +0100 |
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@digia.com> | 2012-11-22 09:10:13 +0100 |
| commit | 470286ecfe79d59df14944e5b5d34630fc739391 (patch) | |
| tree | 43983212872e06cebefd2ae474418fa2908ca54c /Source/WebCore/rendering | |
| parent | 23037105e948c2065da5a937d3a2396b0ff45c1e (diff) | |
| download | qtwebkit-470286ecfe79d59df14944e5b5d34630fc739391.tar.gz | |
Imported WebKit commit e89504fa9195b2063b2530961d4b73dd08de3242 (http://svn.webkit.org/repository/webkit/trunk@135485)
Change-Id: I03774e5ac79721c13ffa30d152537a74d0b12e66
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'Source/WebCore/rendering')
87 files changed, 4482 insertions, 2966 deletions
diff --git a/Source/WebCore/rendering/ExclusionPolygon.cpp b/Source/WebCore/rendering/ExclusionPolygon.cpp index efb6acddb..21beac1ec 100644 --- a/Source/WebCore/rendering/ExclusionPolygon.cpp +++ b/Source/WebCore/rendering/ExclusionPolygon.cpp @@ -190,13 +190,13 @@ static inline bool getVertexIntersectionVertices(const EdgeIntersection& interse if ((intersection.type == VertexMinY && (thisEdge.vertex1().y() < thisEdge.vertex2().y())) || (intersection.type == VertexMaxY && (thisEdge.vertex1().y() > thisEdge.vertex2().y()))) { - prevVertex = polygon.vertexAt(thisEdge.previousEdge().vertexIndex2); + prevVertex = polygon.vertexAt(thisEdge.previousEdge().vertexIndex1); thisVertex = polygon.vertexAt(thisEdge.vertexIndex1); nextVertex = polygon.vertexAt(thisEdge.vertexIndex2); } else { prevVertex = polygon.vertexAt(thisEdge.vertexIndex1); thisVertex = polygon.vertexAt(thisEdge.vertexIndex2); - nextVertex = polygon.vertexAt(thisEdge.nextEdge().vertexIndex1); + nextVertex = polygon.vertexAt(thisEdge.nextEdge().vertexIndex2); } return true; @@ -219,7 +219,7 @@ static bool compareEdgeIntersectionX(const EdgeIntersection& intersection1, cons return (x1 == x2) ? intersection1.type < intersection2.type : x1 < x2; } -void ExclusionPolygon::computeXIntersections(float y, Vector<ExclusionInterval>& result) const +void ExclusionPolygon::computeXIntersections(float y, bool isMinY, Vector<ExclusionInterval>& result) const { Vector<ExclusionPolygon::EdgeInterval> overlappingEdges; m_edgeTree.allOverlaps(ExclusionPolygon::EdgeInterval(y, y, 0), overlappingEdges); @@ -265,19 +265,19 @@ void ExclusionPolygon::computeXIntersections(float y, Vector<ExclusionInterval>& } if (evenOddCrossing) { - bool edgeCrossing = false; - if (thisIntersection.type == Normal || !inside || index == intersections.size() - 1) - edgeCrossing = true; - else { + bool edgeCrossing = thisIntersection.type == Normal; + if (!edgeCrossing) { FloatPoint prevVertex; FloatPoint thisVertex; FloatPoint nextVertex; if (getVertexIntersectionVertices(thisIntersection, prevVertex, thisVertex, nextVertex)) { - if (prevVertex.y() == y) - edgeCrossing = (thisVertex.x() > prevVertex.x()) ? nextVertex.y() > y : nextVertex.y() < y; + if (nextVertex.y() == y) + edgeCrossing = (isMinY) ? prevVertex.y() > y : prevVertex.y() < y; + else if (prevVertex.y() == y) + edgeCrossing = (isMinY) ? nextVertex.y() > y : nextVertex.y() < y; else - edgeCrossing = (nextVertex.y() != y); + edgeCrossing = true; } } if (edgeCrossing) @@ -331,8 +331,8 @@ void ExclusionPolygon::getExcludedIntervals(float logicalTop, float logicalHeigh float y2 = maxYForLogicalLine(logicalTop, logicalHeight); Vector<ExclusionInterval> y1XIntervals, y2XIntervals; - computeXIntersections(y1, y1XIntervals); - computeXIntersections(y2, y2XIntervals); + computeXIntersections(y1, true, y1XIntervals); + computeXIntersections(y2, false, y2XIntervals); Vector<ExclusionInterval> mergedIntervals; mergeExclusionIntervals(y1XIntervals, y2XIntervals, mergedIntervals); @@ -358,8 +358,8 @@ void ExclusionPolygon::getIncludedIntervals(float logicalTop, float logicalHeigh float y2 = maxYForLogicalLine(logicalTop, logicalHeight); Vector<ExclusionInterval> y1XIntervals, y2XIntervals; - computeXIntersections(y1, y1XIntervals); - computeXIntersections(y2, y2XIntervals); + computeXIntersections(y1, true, y1XIntervals); + computeXIntersections(y2, false, y2XIntervals); Vector<ExclusionInterval> commonIntervals; intersectExclusionIntervals(y1XIntervals, y2XIntervals, commonIntervals); diff --git a/Source/WebCore/rendering/ExclusionPolygon.h b/Source/WebCore/rendering/ExclusionPolygon.h index ce7a23c0d..647eb172e 100644 --- a/Source/WebCore/rendering/ExclusionPolygon.h +++ b/Source/WebCore/rendering/ExclusionPolygon.h @@ -68,7 +68,7 @@ public: virtual void getIncludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE; private: - void computeXIntersections(float y, Vector<ExclusionInterval>&) const; + void computeXIntersections(float y, bool isMinY, Vector<ExclusionInterval>&) const; void computeEdgeIntersections(float minY, float maxY, Vector<ExclusionInterval>&) const; unsigned findNextEdgeVertexIndex(unsigned vertexIndex1, bool clockwise) const; @@ -102,7 +102,7 @@ struct ExclusionPolygonEdge { const ExclusionPolygonEdge& previousEdge() const { ASSERT(polygon && polygon->numberOfEdges() > 1); - return polygon->edgeAt((edgeIndex + polygon->numberOfEdges() - 2) % polygon->numberOfEdges()); + return polygon->edgeAt((edgeIndex + polygon->numberOfEdges() - 1) % polygon->numberOfEdges()); } const ExclusionPolygonEdge& nextEdge() const diff --git a/Source/WebCore/rendering/ExclusionShape.cpp b/Source/WebCore/rendering/ExclusionShape.cpp index f5d85b2ec..5e0ea8bf1 100644 --- a/Source/WebCore/rendering/ExclusionShape.cpp +++ b/Source/WebCore/rendering/ExclusionShape.cpp @@ -70,8 +70,7 @@ static PassOwnPtr<ExclusionShape> createExclusionPolygon(PassOwnPtr<Vector<Float PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape* basicShape, float logicalBoxWidth, float logicalBoxHeight, WritingMode writingMode) { - if (!basicShape) - return nullptr; + ASSERT(basicShape); bool horizontalWritingMode = isHorizontalWritingMode(writingMode); float boxWidth = horizontalWritingMode ? logicalBoxWidth : logicalBoxHeight; diff --git a/Source/WebCore/rendering/ExclusionShapeInsideInfo.cpp b/Source/WebCore/rendering/ExclusionShapeInsideInfo.cpp index b7830f10e..934e3f299 100644 --- a/Source/WebCore/rendering/ExclusionShapeInsideInfo.cpp +++ b/Source/WebCore/rendering/ExclusionShapeInsideInfo.cpp @@ -72,7 +72,8 @@ ExclusionShapeInsideInfo* ExclusionShapeInsideInfo::exclusionShapeInsideInfoForR bool ExclusionShapeInsideInfo::isExclusionShapeInsideInfoEnabledForRenderBlock(const RenderBlock* block) { // FIXME: Bug 89707: Enable shape inside for non-rectangular shapes - BasicShape* shape = block->style()->shapeInside(); + ExclusionShapeValue* shapeValue = block->style()->shapeInside(); + BasicShape* shape = (shapeValue && shapeValue->type() == ExclusionShapeValue::SHAPE) ? shapeValue->shape() : 0; return shape && (shape->type() == BasicShape::BASIC_SHAPE_RECTANGLE || shape->type() == BasicShape::BASIC_SHAPE_POLYGON); } @@ -93,7 +94,9 @@ void ExclusionShapeInsideInfo::computeShapeSize(LayoutUnit logicalWidth, LayoutU m_logicalHeight = logicalHeight; // FIXME: Bug 89993: The wrap shape may come from the parent object - BasicShape* shape = m_block->style()->shapeInside(); + ExclusionShapeValue* shapeValue = m_block->style()->shapeInside(); + BasicShape* shape = (shapeValue && shapeValue->type() == ExclusionShapeValue::SHAPE) ? shapeValue->shape() : 0; + ASSERT(shape); m_shape = ExclusionShape::createExclusionShape(shape, logicalWidth, logicalHeight, m_block->style()->writingMode()); diff --git a/Source/WebCore/rendering/FilterEffectRenderer.cpp b/Source/WebCore/rendering/FilterEffectRenderer.cpp index 772bcdb33..e53d338be 100644 --- a/Source/WebCore/rendering/FilterEffectRenderer.cpp +++ b/Source/WebCore/rendering/FilterEffectRenderer.cpp @@ -122,10 +122,10 @@ GraphicsContext* FilterEffectRenderer::inputContext() return sourceImage() ? sourceImage()->context() : 0; } -PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(Document* document, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation* op) +PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(Document* document, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation* filterOperation) { #if ENABLE(SVG) - CachedSVGDocumentReference* cachedSVGDocumentReference = static_cast<CachedSVGDocumentReference*>(op->data()); + CachedSVGDocumentReference* cachedSVGDocumentReference = filterOperation->cachedSVGDocumentReference(); CachedSVGDocument* cachedSVGDocument = cachedSVGDocumentReference ? cachedSVGDocumentReference->document() : 0; // If we have an SVG document, this is an external reference. Otherwise @@ -136,7 +136,7 @@ PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(Document* do if (!document) return 0; - Element* filter = document->getElementById(op->fragment()); + Element* filter = document->getElementById(filterOperation->fragment()); if (!filter) return 0; @@ -171,7 +171,7 @@ PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(Document* do #else UNUSED_PARAM(document); UNUSED_PARAM(previousEffect); - UNUSED_PARAM(op); + UNUSED_PARAM(filterOperation); return 0; #endif } diff --git a/Source/WebCore/rendering/FixedTableLayout.cpp b/Source/WebCore/rendering/FixedTableLayout.cpp index 2a08ad6b5..e75764ac7 100644 --- a/Source/WebCore/rendering/FixedTableLayout.cpp +++ b/Source/WebCore/rendering/FixedTableLayout.cpp @@ -199,7 +199,7 @@ void FixedTableLayout::computePreferredLogicalWidths(LayoutUnit& minWidth, Layou // In this example, the two inner tables should be as large as the outer table. // We can achieve this effect by making the maxwidth of fixed tables with percentage // widths be infinite. - if (m_table->document()->inQuirksMode() && m_table->style()->logicalWidth().isPercent() && maxWidth < tableMaxWidth) + if (m_table->style()->logicalWidth().isPercent() && maxWidth < tableMaxWidth) maxWidth = tableMaxWidth; } diff --git a/Source/WebCore/rendering/HitTestResult.cpp b/Source/WebCore/rendering/HitTestResult.cpp index cc390568c..8553d6f5d 100644 --- a/Source/WebCore/rendering/HitTestResult.cpp +++ b/Source/WebCore/rendering/HitTestResult.cpp @@ -197,19 +197,23 @@ HitTestResult::HitTestResult() : HitTestLocation() { } -HitTestResult::HitTestResult(const LayoutPoint& point) : HitTestLocation(point) +HitTestResult::HitTestResult(const LayoutPoint& point) + : HitTestLocation(point) + , m_pointInMainFrame(point) , m_isOverWidget(false) { } HitTestResult::HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding) : HitTestLocation(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding) + , m_pointInMainFrame(centerPoint) , m_isOverWidget(false) { } HitTestResult::HitTestResult(const HitTestLocation& other) : HitTestLocation(other) + , m_pointInMainFrame(point()) , m_isOverWidget(false) { } @@ -218,6 +222,7 @@ HitTestResult::HitTestResult(const HitTestResult& other) : HitTestLocation(other) , m_innerNode(other.innerNode()) , m_innerNonSharedNode(other.innerNonSharedNode()) + , m_pointInMainFrame(other.m_pointInMainFrame) , m_localPoint(other.localPoint()) , m_innerURLElement(other.URLElement()) , m_scrollbar(other.scrollbar()) @@ -236,6 +241,7 @@ HitTestResult& HitTestResult::operator=(const HitTestResult& other) HitTestLocation::operator=(other); m_innerNode = other.innerNode(); m_innerNonSharedNode = other.innerNonSharedNode(); + m_pointInMainFrame = other.m_pointInMainFrame; m_localPoint = other.localPoint(); m_innerURLElement = other.URLElement(); m_scrollbar = other.scrollbar(); @@ -279,6 +285,15 @@ void HitTestResult::setScrollbar(Scrollbar* s) m_scrollbar = s; } +Frame* HitTestResult::innerNodeFrame() const +{ + if (m_innerNonSharedNode) + return m_innerNonSharedNode->document()->frame(); + if (m_innerNode) + return m_innerNode->document()->frame(); + return 0; +} + Frame* HitTestResult::targetFrame() const { if (!m_innerURLElement) @@ -746,6 +761,7 @@ void HitTestResult::append(const HitTestResult& other) m_innerNode = other.innerNode(); m_innerNonSharedNode = other.innerNonSharedNode(); m_localPoint = other.localPoint(); + m_pointInMainFrame = other.m_pointInMainFrame; m_innerURLElement = other.URLElement(); m_scrollbar = other.scrollbar(); m_isOverWidget = other.isOverWidget(); diff --git a/Source/WebCore/rendering/HitTestResult.h b/Source/WebCore/rendering/HitTestResult.h index 7b3c19e5c..b219a97dc 100644 --- a/Source/WebCore/rendering/HitTestResult.h +++ b/Source/WebCore/rendering/HitTestResult.h @@ -60,7 +60,7 @@ public: ~HitTestLocation(); HitTestLocation& operator=(const HitTestLocation&); - LayoutPoint point() const { return m_point; } + const LayoutPoint& point() const { return m_point; } IntPoint roundedPoint() const { return roundedIntPoint(m_point); } RenderRegion* region() const { return m_region; } @@ -100,7 +100,8 @@ private: bool m_isRectilinear; }; -class HitTestResult : public HitTestLocation { +// FIXME: HitTestResult should not be a HitTestLocation, but instead have a HitTestLocation. See https://bugs.webkit.org/show_bug.cgi?id=101590 +class HitTestResult : protected HitTestLocation { public: typedef ListHashSet<RefPtr<Node> > NodeSet; @@ -115,18 +116,33 @@ public: Node* innerNode() const { return m_innerNode.get(); } Node* innerNonSharedNode() const { return m_innerNonSharedNode.get(); } - LayoutPoint localPoint() const { return m_localPoint; } Element* URLElement() const { return m_innerURLElement.get(); } Scrollbar* scrollbar() const { return m_scrollbar.get(); } bool isOverWidget() const { return m_isOverWidget; } + // Forwarded from HitTestLocation + bool isRectBasedTest() const { return HitTestLocation::isRectBasedTest(); } + + // The hit-tested point in the coordinates of the main frame. + const LayoutPoint& pointInMainFrame() const { return m_pointInMainFrame; } + IntPoint roundedPointInMainFrame() const { return roundedIntPoint(pointInMainFrame()); } + void setPointInMainFrame(const LayoutPoint& p) { m_pointInMainFrame = p; } + + // The hit-tested point in the coordinates of the innerNode frame, the frame containing innerNode. + const LayoutPoint& pointInInnerNodeFrame() const { return HitTestLocation::point(); } + IntPoint roundedPointInInnerNodeFrame() const { return roundedIntPoint(pointInInnerNodeFrame()); } + Frame* innerNodeFrame() const; + + // The hit-tested point in the coordinates of the inner node. + const LayoutPoint& localPoint() const { return m_localPoint; } + void setLocalPoint(const LayoutPoint& p) { m_localPoint = p; } + void setToNonShadowAncestor(); const HitTestLocation& hitTestLocation() const { return *this; } void setInnerNode(Node*); void setInnerNonSharedNode(Node*); - void setLocalPoint(const LayoutPoint& p) { m_localPoint = p; } void setURLElement(Element*); void setScrollbar(Scrollbar*); void setIsOverWidget(bool b) { m_isOverWidget = b; } @@ -185,6 +201,7 @@ private: RefPtr<Node> m_innerNode; RefPtr<Node> m_innerNonSharedNode; + LayoutPoint m_pointInMainFrame; // The hit-tested point in main-frame coordinates. LayoutPoint m_localPoint; // A point in the local coordinate space of m_innerNonSharedNode's renderer. Allows us to efficiently // determine where inside the renderer we hit on subsequent operations. RefPtr<Element> m_innerURLElement; diff --git a/Source/WebCore/rendering/LayoutState.h b/Source/WebCore/rendering/LayoutState.h index 16e01005f..38571f91d 100644 --- a/Source/WebCore/rendering/LayoutState.h +++ b/Source/WebCore/rendering/LayoutState.h @@ -129,6 +129,8 @@ public: ExclusionShapeInsideInfo* m_exclusionShapeInsideInfo; #endif + // FIXME: Distinguish between the layout clip rect and the paint clip rect which may be larger, + // e.g., because of composited scrolling. LayoutRect m_clipRect; // x/y offset from container. Includes relative positioning and scroll offsets. diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index 982b09519..84f7b3c61 100644 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -1398,7 +1398,7 @@ void RenderBlock::layout() } #if ENABLE(CSS_EXCLUSIONS) -void RenderBlock::updateExclusionShapeInsideInfoAfterStyleChange(const BasicShape* shapeInside, const BasicShape* oldShapeInside) +void RenderBlock::updateExclusionShapeInsideInfoAfterStyleChange(const ExclusionShapeValue* shapeInside, const ExclusionShapeValue* oldShapeInside) { // FIXME: A future optimization would do a deep comparison for equality. if (shapeInside == oldShapeInside) @@ -2758,7 +2758,7 @@ void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView // paints the root's background. if (!isRoot()) { - LayoutRect overflowBox = visualOverflowRect(); + LayoutRect overflowBox = overflowRectForPaintRejection(); flipForWritingMode(overflowBox); overflowBox.inflate(maximalOutlineSize(paintInfo.phase)); overflowBox.moveBy(adjustedPaintOffset); diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h index 55a001f61..a5566ed77 100644 --- a/Source/WebCore/rendering/RenderBlock.h +++ b/Source/WebCore/rendering/RenderBlock.h @@ -36,6 +36,7 @@ #if ENABLE(CSS_EXCLUSIONS) #include "ExclusionShapeInsideInfo.h" +#include "ExclusionShapeValue.h" #endif namespace WebCore { @@ -521,7 +522,7 @@ protected: private: #if ENABLE(CSS_EXCLUSIONS) void computeExclusionShapeSize(); - void updateExclusionShapeInsideInfoAfterStyleChange(const BasicShape*, const BasicShape* oldWrapShape); + void updateExclusionShapeInsideInfoAfterStyleChange(const ExclusionShapeValue*, const ExclusionShapeValue* oldExclusionShape); #endif virtual RenderObjectChildList* virtualChildren() { return children(); } virtual const RenderObjectChildList* virtualChildren() const { return children(); } diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index f2fb378f8..654d5ff83 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -448,16 +448,16 @@ FloatQuad RenderBox::absoluteContentQuad() const return localToAbsoluteQuad(FloatRect(rect)); } -LayoutRect RenderBox::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, LayoutPoint* cachedOffsetToRepaintContainer) const +LayoutRect RenderBox::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap) const { LayoutRect box = borderBoundingBox(); adjustRectForOutlineAndShadow(box); - FloatQuad containerRelativeQuad = FloatRect(box); - if (cachedOffsetToRepaintContainer) - containerRelativeQuad.move(cachedOffsetToRepaintContainer->x(), cachedOffsetToRepaintContainer->y()); + FloatQuad containerRelativeQuad; + if (geometryMap) + containerRelativeQuad = geometryMap->mapToContainer(box, repaintContainer); else - containerRelativeQuad = localToContainerQuad(containerRelativeQuad, repaintContainer); + containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); box = containerRelativeQuad.enclosingBoundingBox(); @@ -617,6 +617,11 @@ bool RenderBox::canBeProgramaticallyScrolled() const return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->rendererIsEditable()))) || (node() && node()->isDocumentNode()); } +bool RenderBox::usesCompositedScrolling() const +{ + return hasOverflowClip() && hasLayer() && layer()->usesCompositedScrolling(); +} + void RenderBox::autoscroll() { if (layer()) @@ -652,6 +657,10 @@ void RenderBox::applyCachedClipAndScrollOffsetForRepaint(LayoutRect& paintRect) { paintRect.move(-scrolledContentOffset()); // For overflow:auto/scroll/hidden. + // Do not clip scroll layer contents to reduce the number of repaints while scrolling. + if (usesCompositedScrolling()) + return; + // height() is inaccurate if we're in the middle of a layout of this RenderBox, so use the // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint // anyway if its size does change. @@ -821,11 +830,8 @@ BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsCo FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float>(ctm.yScale())); if (borderObscuresBackgroundEdge(contextScaling)) return BackgroundBleedShrinkBackground; - - // FIXME: there is one more strategy possible, for opaque backgrounds and - // translucent borders. In that case we could avoid using a transparency layer, - // and paint the border first, and then paint the background clipped to the - // inside of the border. + if (!style->hasAppearance() && borderObscuresBackground() && backgroundIsSingleOpaqueLayer()) + return BackgroundBleedBackgroundOverBorder; return BackgroundBleedUseTransparencyLayer; } @@ -859,12 +865,15 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai paintInfo.context->addRoundedRectClip(border); paintInfo.context->beginTransparencyLayer(1); } - + // If we have a native theme appearance, paint that before painting our background. // The theme will tell us whether or not we should also paint the CSS background. IntRect snappedPaintRect(pixelSnappedIntRect(paintRect)); bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, snappedPaintRect); if (!themePainted) { + if (bleedAvoidance == BackgroundBleedBackgroundOverBorder) + paintBorder(paintInfo, paintRect, style(), bleedAvoidance); + paintBackground(paintInfo, paintRect, bleedAvoidance); if (style()->hasAppearance()) @@ -873,7 +882,7 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai paintBoxShadow(paintInfo, paintRect, style(), Inset); // The theme will tell us whether or not we should also paint the CSS border. - if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, snappedPaintRect))) && style()->hasBorder()) + if (bleedAvoidance != BackgroundBleedBackgroundOverBorder && (!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, snappedPaintRect))) && style()->hasBorder()) paintBorder(paintInfo, paintRect, style(), bleedAvoidance); if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) @@ -894,6 +903,25 @@ void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& pa } } +bool RenderBox::backgroundIsSingleOpaqueLayer() const +{ + const FillLayer* fillLayer = style()->backgroundLayers(); + if (!fillLayer || fillLayer->next() || fillLayer->clip() != BorderFillBox || fillLayer->composite() != CompositeSourceOver) + return false; + + // Clipped with local scrolling + if (hasOverflowClip() && fillLayer->attachment() == LocalBackgroundAttachment) + return false; + + Color bgColor = style()->visitedDependentColor(CSSPropertyBackgroundColor); + if (bgColor.isValid() && bgColor.alpha() == 255) + return true; + + // FIXME: return true if a background image is present and is opaque + + return false; +} + void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask || paintInfo.context->paintingDisabled()) @@ -1355,6 +1383,8 @@ const RenderObject* RenderBox::pushMappingToContainer(const RenderLayerModelObje bool offsetDependsOnPoint = false; LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint); + if (geometryMap.mapCoordinatesFlags() & SnapOffsetForTransforms) + containerOffset = roundedIntSize(containerOffset); if (container->isRenderFlowThread()) offsetDependsOnPoint = true; @@ -1566,7 +1596,7 @@ void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintConta // We are now in our parent container's coordinate space. Apply our transform to obtain a bounding box // in the parent's coordinate space that encloses us. - if (layer() && layer()->transform()) { + if (hasLayer() && layer()->transform()) { fixed = position == FixedPosition; rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect)); topLeft = rect.location(); @@ -1584,14 +1614,11 @@ void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintConta topLeft += layer()->offsetForInFlowPosition(); } - if (o->isBlockFlow() && position != AbsolutePosition && position != FixedPosition) { - RenderBlock* cb = toRenderBlock(o); - if (cb->hasColumns()) { - LayoutRect repaintRect(topLeft, rect.size()); - cb->adjustRectForColumns(repaintRect); - topLeft = repaintRect.location(); - rect = repaintRect; - } + if (position != AbsolutePosition && position != FixedPosition && o->hasColumns() && o->isBlockFlow()) { + LayoutRect repaintRect(topLeft, rect.size()); + toRenderBlock(o)->adjustRectForColumns(repaintRect); + topLeft = repaintRect.location(); + rect = repaintRect; } // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout, @@ -3928,6 +3955,17 @@ LayoutRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) return rect; } +LayoutRect RenderBox::overflowRectForPaintRejection() const +{ + LayoutRect overflowRect = visualOverflowRect(); + if (!m_overflow || !usesCompositedScrolling()) + return overflowRect; + + overflowRect.unite(layoutOverflowRect()); + overflowRect.move(-scrolledContentOffset()); + return overflowRect; +} + LayoutUnit RenderBox::offsetLeft() const { return adjustedPositionRelativeToOffsetParent(topLeftLocation()).x(); diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h index e5d1c8306..156b72921 100644 --- a/Source/WebCore/rendering/RenderBox.h +++ b/Source/WebCore/rendering/RenderBox.h @@ -154,7 +154,7 @@ public: LayoutRect computedCSSContentBoxRect() const { return LayoutRect(borderLeft() + computedCSSPaddingLeft(), borderTop() + computedCSSPaddingTop(), clientWidth() - computedCSSPaddingLeft() - computedCSSPaddingRight(), clientHeight() - computedCSSPaddingTop() - computedCSSPaddingBottom()); } // Bounds of the outline box in absolute coords. Respects transforms - virtual LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* /*repaintContainer*/, LayoutPoint* cachedOffsetToRepaintContainer) const OVERRIDE; + virtual LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* /*repaintContainer*/, const RenderGeometryMap*) const OVERRIDE; virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&); // Use this with caution! No type checking is done! @@ -175,6 +175,8 @@ public: virtual LayoutRect visualOverflowRect() const { return m_overflow ? m_overflow->visualOverflowRect() : borderBoxRect(); } LayoutUnit logicalLeftVisualOverflow() const { return style()->isHorizontalWritingMode() ? visualOverflowRect().x() : visualOverflowRect().y(); } LayoutUnit logicalRightVisualOverflow() const { return style()->isHorizontalWritingMode() ? visualOverflowRect().maxX() : visualOverflowRect().maxY(); } + + LayoutRect overflowRectForPaintRejection() const; void addLayoutOverflow(const LayoutRect&); void addVisualOverflow(const LayoutRect&); @@ -433,6 +435,7 @@ public: bool scrollsOverflow() const { return scrollsOverflowX() || scrollsOverflowY(); } bool scrollsOverflowX() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || hasAutoHorizontalScrollbar()); } bool scrollsOverflowY() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || hasAutoVerticalScrollbar()); } + bool usesCompositedScrolling() const; bool hasUnsplittableScrollingOverflow() const; bool isUnsplittableForPagination() const; @@ -567,6 +570,7 @@ protected: void paintMaskImages(const PaintInfo&, const LayoutRect&); BackgroundBleedAvoidance determineBackgroundBleedAvoidance(GraphicsContext*) const; + bool backgroundIsSingleOpaqueLayer() const; #if PLATFORM(MAC) void paintCustomHighlight(const LayoutPoint&, const AtomicString& type, bool behindText); diff --git a/Source/WebCore/rendering/RenderBoxModelObject.cpp b/Source/WebCore/rendering/RenderBoxModelObject.cpp index 1277a7c7f..f9a994f4d 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.cpp +++ b/Source/WebCore/rendering/RenderBoxModelObject.cpp @@ -26,7 +26,6 @@ #include "config.h" #include "RenderBoxModelObject.h" -#include "FilterOperations.h" #include "GraphicsContext.h" #include "HTMLFrameOwnerElement.h" #include "HTMLNames.h" @@ -647,7 +646,7 @@ LayoutUnit RenderBoxModelObject::computedCSSPaddingEnd() const } RoundedRect RenderBoxModelObject::getBackgroundRoundedRect(const LayoutRect& borderRect, InlineFlowBox* box, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHeight, - bool includeLogicalLeftEdge, bool includeLogicalRightEdge) + bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const { RenderView* renderView = view(); RoundedRect border = style()->getRoundedBorderFor(borderRect, renderView, includeLogicalLeftEdge, includeLogicalRightEdge); @@ -691,17 +690,31 @@ void RenderBoxModelObject::clipRoundedInnerRect(GraphicsContext * context, const } } -static LayoutRect backgroundRectAdjustedForBleedAvoidance(GraphicsContext* context, const LayoutRect& borderRect, BackgroundBleedAvoidance bleedAvoidance) +static LayoutRect shrinkRectByOnePixel(GraphicsContext* context, const LayoutRect& rect) { - if (bleedAvoidance != BackgroundBleedShrinkBackground) - return borderRect; - - // We shrink the rectangle by one pixel on each side because the bleed is one pixel maximum. + LayoutRect shrunkRect = rect; AffineTransform transform = context->getCTM(); - LayoutRect adjustedRect = borderRect; - adjustedRect.inflateX(-static_cast<LayoutUnit>(ceil(1 / transform.xScale()))); - adjustedRect.inflateY(-static_cast<LayoutUnit>(ceil(1 / transform.yScale()))); - return adjustedRect; + shrunkRect.inflateX(-static_cast<LayoutUnit>(ceil(1 / transform.xScale()))); + shrunkRect.inflateY(-static_cast<LayoutUnit>(ceil(1 / transform.yScale()))); + return shrunkRect; +} + +LayoutRect RenderBoxModelObject::borderInnerRectAdjustedForBleedAvoidance(GraphicsContext* context, const LayoutRect& rect, BackgroundBleedAvoidance bleedAvoidance) const +{ + // We shrink the rectangle by one pixel on each side to make it fully overlap the anti-aliased background border + return (bleedAvoidance == BackgroundBleedBackgroundOverBorder) ? shrinkRectByOnePixel(context, rect) : rect; +} + +RoundedRect RenderBoxModelObject::backgroundRoundedRectAdjustedForBleedAvoidance(GraphicsContext* context, const LayoutRect& borderRect, BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSize& boxSize, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const +{ + if (bleedAvoidance == BackgroundBleedShrinkBackground) { + // We shrink the rectangle by one pixel on each side because the bleed is one pixel maximum. + return getBackgroundRoundedRect(shrinkRectByOnePixel(context, borderRect), box, boxSize.width(), boxSize.height(), includeLogicalLeftEdge, includeLogicalRightEdge); + } + if (bleedAvoidance == BackgroundBleedBackgroundOverBorder) + return style()->getRoundedInnerBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge); + + return getBackgroundRoundedRect(borderRect, box, boxSize.width(), boxSize.height(), includeLogicalLeftEdge, includeLogicalRightEdge); } static void applyBoxShadowForBackground(GraphicsContext* context, RenderStyle* style) @@ -773,7 +786,7 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co applyBoxShadowForBackground(context, style()); if (hasRoundedBorder && bleedAvoidance != BackgroundBleedUseTransparencyLayer) { - RoundedRect border = getBackgroundRoundedRect(backgroundRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance), box, boxSize.width(), boxSize.height(), includeLeftEdge, includeRightEdge); + RoundedRect border = backgroundRoundedRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge); context->fillRoundedRect(border, bgColor, style()->colorSpace()); } else context->fillRect(pixelSnappedIntRect(rect), bgColor, style()->colorSpace()); @@ -785,8 +798,7 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co bool clipToBorderRadius = hasRoundedBorder && !(isBorderFill && bleedAvoidance == BackgroundBleedUseTransparencyLayer); GraphicsContextStateSaver clipToBorderStateSaver(*context, clipToBorderRadius); if (clipToBorderRadius) { - LayoutRect adjustedRect = isBorderFill ? backgroundRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance) : rect; - RoundedRect border = getBackgroundRoundedRect(adjustedRect, box, boxSize.width(), boxSize.height(), includeLeftEdge, includeRightEdge); + RoundedRect border = isBorderFill ? backgroundRoundedRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge) : getBackgroundRoundedRect(rect, box, boxSize.width(), boxSize.height(), includeLeftEdge, includeRightEdge); // Clip to the padding or content boxes as necessary. if (bgLayer->clip() == ContentFillBox) { @@ -1729,8 +1741,8 @@ static IntRect calculateSideRect(const RoundedRect& outerBorder, const BorderEdg } void RenderBoxModelObject::paintBorderSides(GraphicsContext* graphicsContext, const RenderStyle* style, const RoundedRect& outerBorder, const RoundedRect& innerBorder, - const BorderEdge edges[], BorderEdgeFlags edgeSet, BackgroundBleedAvoidance bleedAvoidance, - bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias, const Color* overrideColor) + const IntPoint& innerBorderAdjustment, const BorderEdge edges[], BorderEdgeFlags edgeSet, BackgroundBleedAvoidance bleedAvoidance, + bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias, const Color* overrideColor) { bool renderRadii = outerBorder.isRounded(); @@ -1738,9 +1750,14 @@ void RenderBoxModelObject::paintBorderSides(GraphicsContext* graphicsContext, co if (renderRadii) roundedPath.addRoundedRect(outerBorder); + // The inner border adjustment for bleed avoidance mode BackgroundBleedBackgroundOverBorder + // is only applied to sideRect, which is okay since BackgroundBleedBackgroundOverBorder + // is only to be used for solid borders and the shape of the border painted by drawBoxSideFromPath + // only depends on sideRect when painting solid borders. + if (edges[BSTop].shouldRender() && includesEdge(edgeSet, BSTop)) { IntRect sideRect = outerBorder.rect(); - sideRect.setHeight(edges[BSTop].width); + sideRect.setHeight(edges[BSTop].width + innerBorderAdjustment.y()); bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSTop].style) || borderWillArcInnerEdge(innerBorder.radii().topLeft(), innerBorder.radii().topRight())); paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSTop, BSLeft, BSRight, edges, usePath ? &roundedPath : 0, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor); @@ -1748,7 +1765,7 @@ void RenderBoxModelObject::paintBorderSides(GraphicsContext* graphicsContext, co if (edges[BSBottom].shouldRender() && includesEdge(edgeSet, BSBottom)) { IntRect sideRect = outerBorder.rect(); - sideRect.shiftYEdgeTo(sideRect.maxY() - edges[BSBottom].width); + sideRect.shiftYEdgeTo(sideRect.maxY() - edges[BSBottom].width - innerBorderAdjustment.y()); bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSBottom].style) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), innerBorder.radii().bottomRight())); paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSBottom, BSLeft, BSRight, edges, usePath ? &roundedPath : 0, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor); @@ -1756,7 +1773,7 @@ void RenderBoxModelObject::paintBorderSides(GraphicsContext* graphicsContext, co if (edges[BSLeft].shouldRender() && includesEdge(edgeSet, BSLeft)) { IntRect sideRect = outerBorder.rect(); - sideRect.setWidth(edges[BSLeft].width); + sideRect.setWidth(edges[BSLeft].width + innerBorderAdjustment.x()); bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSLeft].style) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), innerBorder.radii().topLeft())); paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSLeft, BSTop, BSBottom, edges, usePath ? &roundedPath : 0, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor); @@ -1764,17 +1781,16 @@ void RenderBoxModelObject::paintBorderSides(GraphicsContext* graphicsContext, co if (edges[BSRight].shouldRender() && includesEdge(edgeSet, BSRight)) { IntRect sideRect = outerBorder.rect(); - sideRect.shiftXEdgeTo(sideRect.maxX() - edges[BSRight].width); + sideRect.shiftXEdgeTo(sideRect.maxX() - edges[BSRight].width - innerBorderAdjustment.x()); bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSRight].style) || borderWillArcInnerEdge(innerBorder.radii().bottomRight(), innerBorder.radii().topRight())); paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSRight, BSTop, BSBottom, edges, usePath ? &roundedPath : 0, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor); } } -void RenderBoxModelObject::paintTranslucentBorderSides(GraphicsContext* graphicsContext, const RenderStyle* style, const RoundedRect& outerBorder, const RoundedRect& innerBorder, - const BorderEdge edges[], BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias) +void RenderBoxModelObject::paintTranslucentBorderSides(GraphicsContext* graphicsContext, const RenderStyle* style, const RoundedRect& outerBorder, const RoundedRect& innerBorder, const IntPoint& innerBorderAdjustment, + const BorderEdge edges[], BorderEdgeFlags edgesToDraw, BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias) { - BorderEdgeFlags edgesToDraw = AllBorderEdges; while (edgesToDraw) { // Find undrawn edges sharing a color. Color commonColor; @@ -1802,7 +1818,7 @@ void RenderBoxModelObject::paintTranslucentBorderSides(GraphicsContext* graphics commonColor = Color(commonColor.red(), commonColor.green(), commonColor.blue()); } - paintBorderSides(graphicsContext, style, outerBorder, innerBorder, edges, commonColorEdgeSet, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, &commonColor); + paintBorderSides(graphicsContext, style, outerBorder, innerBorder, innerBorderAdjustment, edges, commonColorEdgeSet, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, &commonColor); if (useTransparencyLayer) graphicsContext->endTransparencyLayer(); @@ -1825,7 +1841,7 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& BorderEdge edges[4]; getBorderEdgeInfo(edges, style, includeLogicalLeftEdge, includeLogicalRightEdge); RoundedRect outerBorder = style->getRoundedBorderFor(rect, view(), includeLogicalLeftEdge, includeLogicalRightEdge); - RoundedRect innerBorder = style->getRoundedInnerBorderFor(rect, includeLogicalLeftEdge, includeLogicalRightEdge); + RoundedRect innerBorder = style->getRoundedInnerBorderFor(borderInnerRectAdjustedForBleedAvoidance(graphicsContext, rect, bleedAvoidance), includeLogicalLeftEdge, includeLogicalRightEdge); bool haveAlphaColor = false; bool haveAllSolidEdges = true; @@ -1833,9 +1849,14 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& int numEdgesVisible = 4; bool allEdgesShareColor = true; int firstVisibleEdge = -1; + BorderEdgeFlags edgesToDraw = 0; for (int i = BSTop; i <= BSLeft; ++i) { const BorderEdge& currEdge = edges[i]; + + if (edges[i].shouldRender()) + edgesToDraw |= edgeFlagForSide(static_cast<BoxSide>(i)); + if (currEdge.presentButInvisible()) { --numEdgesVisible; allEdgesShareColor = false; @@ -1961,10 +1982,12 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& // If only one edge visible antialiasing doesn't create seams bool antialias = shouldAntialiasLines(graphicsContext) || numEdgesVisible == 1; + RoundedRect unadjustedInnerBorder = (bleedAvoidance == BackgroundBleedBackgroundOverBorder) ? style->getRoundedInnerBorderFor(rect, includeLogicalLeftEdge, includeLogicalRightEdge) : innerBorder; + IntPoint innerBorderAdjustment(innerBorder.rect().x() - unadjustedInnerBorder.rect().x(), innerBorder.rect().y() - unadjustedInnerBorder.rect().y()); if (haveAlphaColor) - paintTranslucentBorderSides(graphicsContext, style, outerBorder, innerBorder, edges, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias); + paintTranslucentBorderSides(graphicsContext, style, outerBorder, unadjustedInnerBorder, innerBorderAdjustment, edges, edgesToDraw, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias); else - paintBorderSides(graphicsContext, style, outerBorder, innerBorder, edges, AllBorderEdges, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias); + paintBorderSides(graphicsContext, style, outerBorder, unadjustedInnerBorder, innerBorderAdjustment, edges, edgesToDraw, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias); } void RenderBoxModelObject::drawBoxSideFromPath(GraphicsContext* graphicsContext, const LayoutRect& borderRect, const Path& borderPath, const BorderEdge edges[], diff --git a/Source/WebCore/rendering/RenderBoxModelObject.h b/Source/WebCore/rendering/RenderBoxModelObject.h index 1cfe4123e..eea0d6893 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.h +++ b/Source/WebCore/rendering/RenderBoxModelObject.h @@ -38,7 +38,8 @@ typedef unsigned BorderEdgeFlags; enum BackgroundBleedAvoidance { BackgroundBleedNone, BackgroundBleedShrinkBackground, - BackgroundBleedUseTransparencyLayer + BackgroundBleedUseTransparencyLayer, + BackgroundBleedBackgroundOverBorder }; enum ContentChangeType { @@ -151,7 +152,7 @@ public: bool paintNinePieceImage(GraphicsContext*, const LayoutRect&, const RenderStyle*, const NinePieceImage&, CompositeOperator = CompositeSourceOver); void paintBoxShadow(const PaintInfo&, const LayoutRect&, const RenderStyle*, ShadowStyle, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true); void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, BackgroundBleedAvoidance, InlineFlowBox* = 0, const LayoutSize& = LayoutSize(), CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0); - + virtual bool boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance, InlineFlowBox* = 0) const; // Overridden by subclasses to determine line height and baseline position. @@ -233,6 +234,8 @@ protected: void getBorderEdgeInfo(class BorderEdge[], const RenderStyle*, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; bool borderObscuresBackgroundEdge(const FloatSize& contextScale) const; bool borderObscuresBackground() const; + RoundedRect backgroundRoundedRectAdjustedForBleedAvoidance(GraphicsContext*, const LayoutRect&, BackgroundBleedAvoidance, InlineFlowBox*, const LayoutSize&, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const; + LayoutRect borderInnerRectAdjustedForBleedAvoidance(GraphicsContext*, const LayoutRect&, BackgroundBleedAvoidance) const; bool shouldPaintAtLowQuality(GraphicsContext*, Image*, const void*, const LayoutSize&); @@ -285,7 +288,7 @@ private: IntSize calculateImageIntrinsicDimensions(StyleImage*, const IntSize& scaledPositioningAreaSize, ScaleByEffectiveZoomOrNot) const; RoundedRect getBackgroundRoundedRect(const LayoutRect&, InlineFlowBox*, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHeight, - bool includeLogicalLeftEdge, bool includeLogicalRightEdge); + bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const; void clipBorderSidePolygon(GraphicsContext*, const RoundedRect& outerBorder, const RoundedRect& innerBorder, @@ -294,11 +297,11 @@ private: void paintOneBorderSide(GraphicsContext*, const RenderStyle*, const RoundedRect& outerBorder, const RoundedRect& innerBorder, const IntRect& sideRect, BoxSide, BoxSide adjacentSide1, BoxSide adjacentSide2, const class BorderEdge[], const Path*, BackgroundBleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias, const Color* overrideColor = 0); - void paintTranslucentBorderSides(GraphicsContext*, const RenderStyle*, const RoundedRect& outerBorder, const RoundedRect& innerBorder, - const class BorderEdge[], BackgroundBleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias = false); + void paintTranslucentBorderSides(GraphicsContext*, const RenderStyle*, const RoundedRect& outerBorder, const RoundedRect& innerBorder, const IntPoint& innerBorderAdjustment, + const class BorderEdge[], BorderEdgeFlags, BackgroundBleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias = false); void paintBorderSides(GraphicsContext*, const RenderStyle*, const RoundedRect& outerBorder, const RoundedRect& innerBorder, - const class BorderEdge[], BorderEdgeFlags, BackgroundBleedAvoidance, - bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias = false, const Color* overrideColor = 0); + const IntPoint& innerBorderAdjustment, const class BorderEdge[], BorderEdgeFlags, BackgroundBleedAvoidance, + bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias = false, const Color* overrideColor = 0); void drawBoxSideFromPath(GraphicsContext*, const LayoutRect&, const Path&, const class BorderEdge[], float thickness, float drawThickness, BoxSide, const RenderStyle*, Color, EBorderStyle, BackgroundBleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge); diff --git a/Source/WebCore/rendering/RenderEmbeddedObject.h b/Source/WebCore/rendering/RenderEmbeddedObject.h index 133f34d92..ef09ebb4d 100644 --- a/Source/WebCore/rendering/RenderEmbeddedObject.h +++ b/Source/WebCore/rendering/RenderEmbeddedObject.h @@ -68,6 +68,9 @@ protected: RenderObjectChildList* children() { return &m_children; } #endif +protected: + virtual void layout() OVERRIDE; + private: virtual const char* renderName() const { return "RenderEmbeddedObject"; } virtual bool isEmbeddedObject() const { return true; } @@ -76,7 +79,6 @@ private: virtual bool requiresLayer() const; #endif - virtual void layout(); virtual void viewCleared(); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp index 2e08a5cdf..e11d865f1 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.cpp +++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp @@ -132,7 +132,7 @@ struct RenderFlexibleBox::Violation { RenderFlexibleBox::RenderFlexibleBox(Node* node) : RenderBlock(node) - , m_numberOfChildrenOnFirstLine(0) + , m_numberOfInFlowChildrenOnFirstLine(-1) { setChildrenInline(false); // All of our children must be block-level. } @@ -254,11 +254,11 @@ int RenderFlexibleBox::firstLineBoxBaseline() const { ASSERT(m_orderIterator); - if (isWritingModeRoot() || !m_numberOfChildrenOnFirstLine) + if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0) return -1; RenderBox* baselineChild = 0; - RenderBox* child = m_orderIterator->first(); - for (size_t childNumber = 0; childNumber < m_numberOfChildrenOnFirstLine; ++childNumber, child = m_orderIterator->next()) { + int childNumber = 0; + for (RenderBox* child = m_orderIterator->first(); child; child = m_orderIterator->next()) { if (child->isOutOfFlowPositioned()) continue; if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child)) { @@ -267,6 +267,10 @@ int RenderFlexibleBox::firstLineBoxBaseline() const } if (!baselineChild) baselineChild = child; + + ++childNumber; + if (childNumber == m_numberOfInFlowChildrenOnFirstLine) + break; } if (!baselineChild) @@ -320,6 +324,7 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit) setLogicalHeight(0); updateLogicalWidth(); + m_numberOfInFlowChildrenOnFirstLine = -1; m_overflow.clear(); RenderBlock::startDelayUpdateScrollInfo(); @@ -386,8 +391,6 @@ void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(OrderIterator& flipForWrapReverse(iterator, lineContexts, crossAxisStartEdge); } - m_numberOfChildrenOnFirstLine = lineContexts.isEmpty() ? 0 : lineContexts[0].numberOfChildren; - // direction:rtl + flex-direction:column means the cross-axis direction is flipped. flipForRightToLeftColumn(iterator); } @@ -1132,6 +1135,8 @@ void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, cons layoutColumnReverse(children, crossAxisOffset, availableFreeSpace); } + if (m_numberOfInFlowChildrenOnFirstLine == -1) + m_numberOfInFlowChildrenOnFirstLine = seenInFlowPositionedChildren; lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent)); crossAxisOffset += maxChildCrossAxisExtent; } diff --git a/Source/WebCore/rendering/RenderFlexibleBox.h b/Source/WebCore/rendering/RenderFlexibleBox.h index acbdba928..98eafca7c 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.h +++ b/Source/WebCore/rendering/RenderFlexibleBox.h @@ -146,7 +146,7 @@ private: void flipForWrapReverse(OrderIterator&, const WTF::Vector<LineContext>&, LayoutUnit crossAxisStartEdge); OwnPtr<OrderIterator> m_orderIterator; - size_t m_numberOfChildrenOnFirstLine; + int m_numberOfInFlowChildrenOnFirstLine; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderFlowThread.cpp b/Source/WebCore/rendering/RenderFlowThread.cpp index ce182cd06..13809b00d 100644 --- a/Source/WebCore/rendering/RenderFlowThread.cpp +++ b/Source/WebCore/rendering/RenderFlowThread.cpp @@ -856,7 +856,7 @@ bool RenderFlowThread::addForcedRegionBreak(LayoutUnit offsetBreakInFlowThread, RenderRegionList::iterator regionIter = m_regionList.find(region); ASSERT(regionIter != m_regionList.end()); - for (; (regionIter != m_regionList.end()) && (currentRegionOffsetInFlowThread < offsetBreakInFlowThread); ++regionIter) { + for (; regionIter != m_regionList.end(); ++regionIter) { RenderRegion* region = *regionIter; if (region->needsOverrideLogicalContentHeightComputation()) { mapToUse.set(breakChild, region); @@ -871,6 +871,12 @@ bool RenderFlowThread::addForcedRegionBreak(LayoutUnit offsetBreakInFlowThread, currentRegionOffsetInFlowThread += regionOverrideLogicalContentHeight; } else currentRegionOffsetInFlowThread += isHorizontalWritingMode() ? region->flowThreadPortionRect().height() : region->flowThreadPortionRect().width(); + + // If the current offset if greater than the break offset, bail out and skip the current region. + if (currentRegionOffsetInFlowThread >= offsetBreakInFlowThread) { + ++regionIter; + break; + } } // The remaining auto logical height regions in the chain that were unable to receive content diff --git a/Source/WebCore/rendering/RenderGeometryMap.cpp b/Source/WebCore/rendering/RenderGeometryMap.cpp index 5a6a69d9d..74434895f 100644 --- a/Source/WebCore/rendering/RenderGeometryMap.cpp +++ b/Source/WebCore/rendering/RenderGeometryMap.cpp @@ -33,11 +33,12 @@ namespace WebCore { -RenderGeometryMap::RenderGeometryMap() +RenderGeometryMap::RenderGeometryMap(MapCoordinatesFlags flags) : m_insertionPosition(notFound) , m_nonUniformStepsCount(0) , m_transformedStepsCount(0) , m_fixedStepsCount(0) + , m_mapCoordinatesFlags(flags) { } @@ -45,62 +46,30 @@ RenderGeometryMap::~RenderGeometryMap() { } -FloatPoint RenderGeometryMap::absolutePoint(const FloatPoint& p) const -{ - FloatPoint result; - - if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep()) - result = p + m_accumulatedOffset; - else { - TransformState transformState(TransformState::ApplyTransformDirection, p); - mapToAbsolute(transformState); - result = transformState.lastPlanarPoint(); - } - -#if !ASSERT_DISABLED - FloatPoint rendererMappedResult = m_mapping.last().m_renderer->localToAbsolute(p, UseTransforms | SnapOffsetForTransforms); - ASSERT(rendererMappedResult == result); -#endif - - return result; -} - -FloatRect RenderGeometryMap::absoluteRect(const FloatRect& rect) const -{ - FloatRect result; - - if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep()) { - result = rect; - result.move(m_accumulatedOffset); - } else { - TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect); - mapToAbsolute(transformState); - result = transformState.lastPlanarQuad().boundingBox(); - } - -#if !ASSERT_DISABLED - FloatRect rendererMappedResult = m_mapping.last().m_renderer->localToAbsoluteQuad(rect).boundingBox(); - // Inspector creates renderers with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>. - // Taking FloatQuad bounds avoids spurious assertions because of that. - ASSERT(enclosingIntRect(rendererMappedResult) == enclosingIntRect(FloatQuad(result).boundingBox())); -#endif - - return result; -} - -void RenderGeometryMap::mapToAbsolute(TransformState& transformState) const +void RenderGeometryMap::mapToContainer(TransformState& transformState, const RenderLayerModelObject* container) const { // If the mapping includes something like columns, we have to go via renderers. if (hasNonUniformStep()) { - m_mapping.last().m_renderer->mapLocalToContainer(0, transformState, UseTransforms | ApplyContainerFlip | SnapOffsetForTransforms); + m_mapping.last().m_renderer->mapLocalToContainer(container, transformState, ApplyContainerFlip | m_mapCoordinatesFlags); return; } bool inFixed = false; +#if !ASSERT_DISABLED + bool foundContainer = !container || (m_mapping.size() && m_mapping[0].m_renderer == container); +#endif for (int i = m_mapping.size() - 1; i >= 0; --i) { const RenderGeometryMapStep& currentStep = m_mapping[i]; + // If container is the RenderView (step 0) we want to apply its scroll offset. + if (i > 0 && currentStep.m_renderer == container) { +#if !ASSERT_DISABLED + foundContainer = true; +#endif + break; + } + // If this box has a transform, it acts as a fixed position container // for fixed descendants, which prevents the propagation of 'fixed' // unless the layer itself is also fixed position. @@ -110,7 +79,8 @@ void RenderGeometryMap::mapToAbsolute(TransformState& transformState) const inFixed = true; if (!i) { - if (currentStep.m_transform) + // A null container indicates mapping through the RenderView, so including its transform (the page scale). + if (!container && currentStep.m_transform) transformState.applyTransform(*currentStep.m_transform.get()); // The root gets special treatment for fixed position @@ -125,9 +95,57 @@ void RenderGeometryMap::mapToAbsolute(TransformState& transformState) const } } + ASSERT(foundContainer); transformState.flatten(); } +FloatPoint RenderGeometryMap::mapToContainer(const FloatPoint& p, const RenderLayerModelObject* container) const +{ + FloatPoint result; + + if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_renderer))) + result = p + m_accumulatedOffset; + else { + TransformState transformState(TransformState::ApplyTransformDirection, p); + mapToContainer(transformState, container); + result = transformState.lastPlanarPoint(); + } + +#if !ASSERT_DISABLED + FloatPoint rendererMappedResult = m_mapping.last().m_renderer->localToAbsolute(p, m_mapCoordinatesFlags); + ASSERT(roundedIntPoint(rendererMappedResult) == roundedIntPoint(result)); +// if (roundedIntPoint(rendererMappedResult) != roundedIntPoint(result)) +// fprintf(stderr, "Mismatched point\n"); +#endif + + return result; +} + +FloatQuad RenderGeometryMap::mapToContainer(const FloatRect& rect, const RenderLayerModelObject* container) const +{ + FloatRect result; + + if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_renderer))) { + result = rect; + result.move(m_accumulatedOffset); + } else { + TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect); + mapToContainer(transformState, container); + result = transformState.lastPlanarQuad().boundingBox(); + } + +#if !ASSERT_DISABLED + FloatRect rendererMappedResult = m_mapping.last().m_renderer->localToContainerQuad(rect, container, m_mapCoordinatesFlags).boundingBox(); + // Inspector creates renderers with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>. + // Taking FloatQuad bounds avoids spurious assertions because of that. + ASSERT(enclosingIntRect(rendererMappedResult) == enclosingIntRect(FloatQuad(result).boundingBox())); +// if (enclosingIntRect(rendererMappedResult) != enclosingIntRect(FloatQuad(result).boundingBox())) +// fprintf(stderr, "Mismatched rects\n"); +#endif + + return result; +} + void RenderGeometryMap::pushMappingsToAncestor(const RenderObject* renderer, const RenderLayerModelObject* ancestorRenderer) { // We need to push mappings in reverse order here, so do insertions rather than appends. @@ -139,19 +157,23 @@ void RenderGeometryMap::pushMappingsToAncestor(const RenderObject* renderer, con ASSERT(m_mapping.isEmpty() || m_mapping[0].m_renderer->isRenderView()); } -static bool canMapViaLayer(const RenderLayer* layer) +static bool canMapBetweenRenderers(const RenderObject* renderer, const RenderObject* ancestor) { - RenderStyle* style = layer->renderer()->style(); - if (style->position() == FixedPosition || style->isFlippedBlocksWritingMode()) - return false; - - if (layer->renderer()->hasColumns() || layer->renderer()->hasTransform()) - return false; - -#if ENABLE(SVG) - if (layer->renderer()->isSVGRoot()) - return false; -#endif + for (const RenderObject* current = renderer; ; current = current->parent()) { + const RenderStyle* style = current->style(); + if (style->position() == FixedPosition || style->isFlippedBlocksWritingMode()) + return false; + + if (current->hasColumns() || current->hasTransform() || current->isRenderFlowThread()) + return false; + + #if ENABLE(SVG) + if (current->isSVGRoot()) + return false; + #endif + if (current == ancestor) + break; + } return true; } @@ -160,15 +182,23 @@ void RenderGeometryMap::pushMappingsToAncestor(const RenderLayer* layer, const R { const RenderObject* renderer = layer->renderer(); - // The simple case can be handled fast in the layer tree. - bool canConvertInLayerTree = ancestorLayer ? canMapViaLayer(ancestorLayer) : false; - for (const RenderLayer* current = layer; current != ancestorLayer && canConvertInLayerTree; current = current->parent()) - canConvertInLayerTree = canMapViaLayer(current); + // We have to visit all the renderers to detect flipped blocks. This might defeat the gains + // from mapping via layers. + bool canConvertInLayerTree = ancestorLayer ? canMapBetweenRenderers(layer->renderer(), ancestorLayer->renderer()) : false; + +// fprintf(stderr, "RenderGeometryMap::pushMappingsToAncestor from layer %p to layer %p, canConvertInLayerTree=%d\n", layer, ancestorLayer, canConvertInLayerTree); if (canConvertInLayerTree) { - TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size()); LayoutPoint layerOffset; layer->convertToLayerCoords(ancestorLayer, layerOffset); + + // The RenderView must be pushed first. + if (!m_mapping.size()) { + ASSERT(ancestorLayer->renderer()->isRenderView()); + pushMappingsToAncestor(ancestorLayer->renderer(), 0); + } + + TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size()); push(renderer, toLayoutSize(layerOffset), /*accumulatingTransform*/ true, /*isNonUniform*/ false, /*isFixedPosition*/ false, /*hasTransform*/ false); return; } @@ -178,6 +208,8 @@ void RenderGeometryMap::pushMappingsToAncestor(const RenderLayer* layer, const R void RenderGeometryMap::push(const RenderObject* renderer, const LayoutSize& offsetFromContainer, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform) { +// fprintf(stderr, "RenderGeometryMap::push %p %d,%d isNonUniform=%d\n", renderer, offsetFromContainer.width().toInt(), offsetFromContainer.height().toInt(), isNonUniform); + ASSERT(m_insertionPosition != notFound); m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform)); diff --git a/Source/WebCore/rendering/RenderGeometryMap.h b/Source/WebCore/rendering/RenderGeometryMap.h index 15dc884d3..bab106f1d 100644 --- a/Source/WebCore/rendering/RenderGeometryMap.h +++ b/Source/WebCore/rendering/RenderGeometryMap.h @@ -30,6 +30,7 @@ #include "FloatQuad.h" #include "IntSize.h" #include "LayoutSize.h" +#include "RenderObject.h" #include "TransformationMatrix.h" #include <wtf/OwnPtr.h> @@ -37,7 +38,6 @@ namespace WebCore { class RenderLayer; class RenderLayerModelObject; -class RenderObject; class RenderView; class TransformState; @@ -74,11 +74,26 @@ struct RenderGeometryMapStep { class RenderGeometryMap { WTF_MAKE_NONCOPYABLE(RenderGeometryMap); public: - RenderGeometryMap(); + RenderGeometryMap(MapCoordinatesFlags = UseTransforms | SnapOffsetForTransforms); ~RenderGeometryMap(); - FloatPoint absolutePoint(const FloatPoint&) const; - FloatRect absoluteRect(const FloatRect&) const; + MapCoordinatesFlags mapCoordinatesFlags() const { return m_mapCoordinatesFlags; } + + FloatPoint absolutePoint(const FloatPoint& p) const + { + return mapToContainer(p, 0); + } + + FloatRect absoluteRect(const FloatRect& rect) const + { + return mapToContainer(rect, 0).boundingBox(); + } + + // Map to a container. Will assert that the container has been pushed onto this map. + // A null container maps through the RenderView (including its scale transform, if any). + // If the container is the RenderView, the scroll offset is applied, but not the scale. + FloatPoint mapToContainer(const FloatPoint&, const RenderLayerModelObject*) const; + FloatQuad mapToContainer(const FloatRect&, const RenderLayerModelObject*) const; // Called by code walking the renderer or layer trees. void pushMappingsToAncestor(const RenderLayer*, const RenderLayer* ancestorLayer); @@ -97,7 +112,7 @@ public: void pushView(const RenderView*, const LayoutSize& scrollOffset, const TransformationMatrix* = 0); private: - void mapToAbsolute(TransformState&) const; + void mapToContainer(TransformState&, const RenderLayerModelObject* container = 0) const; void stepInserted(const RenderGeometryMapStep&); void stepRemoved(const RenderGeometryMapStep&); @@ -114,6 +129,7 @@ private: int m_fixedStepsCount; RenderGeometryMapSteps m_mapping; LayoutSize m_accumulatedOffset; + MapCoordinatesFlags m_mapCoordinatesFlags; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderGrid.cpp b/Source/WebCore/rendering/RenderGrid.cpp index 6e293cc0c..e520581b9 100644 --- a/Source/WebCore/rendering/RenderGrid.cpp +++ b/Source/WebCore/rendering/RenderGrid.cpp @@ -175,23 +175,33 @@ void RenderGrid::layoutGridItems() setLogicalHeight(logicalHeight() + rowTracks[i].m_usedBreadth); } -LayoutPoint RenderGrid::findChildLogicalPosition(RenderBox* child, const Vector<GridTrack>& columnTracks, const Vector<GridTrack>& rowTracks) +size_t RenderGrid::resolveGridPosition(const GridPosition& position) const { - Length column = child->style()->gridItemColumn(); - Length row = child->style()->gridItemRow(); - - // FIXME: What does a non-positive integer mean for a column/row? - if (!column.isPositive() || !row.isPositive()) - return LayoutPoint(); - // FIXME: Handle other values for grid-{row,column} like ranges or line names. - if (!column.isFixed() || !row.isFixed()) - return LayoutPoint(); + switch (position.type()) { + case IntegerPosition: + // FIXME: What does a non-positive integer mean for a column/row? + if (!position.isPositive()) + return 0; + + return position.integerPosition() - 1; + case AutoPosition: + // FIXME: We should follow 'grid-auto-flow' for resolution. + // Until then, we use the 'grid-auto-flow: none' behavior (which is the default) + // and resolve 'auto' as the first row / column. + return 0; + } + ASSERT_NOT_REACHED(); + return 0; +} - size_t columnTrack = static_cast<size_t>(column.intValue()) - 1; - size_t rowTrack = static_cast<size_t>(row.intValue()) - 1; +LayoutPoint RenderGrid::findChildLogicalPosition(RenderBox* child, const Vector<GridTrack>& columnTracks, const Vector<GridTrack>& rowTracks) +{ + size_t columnTrack = resolveGridPosition(child->style()->gridItemColumn()); + size_t rowTrack = resolveGridPosition(child->style()->gridItemRow()); LayoutPoint offset; + // FIXME: |columnTrack| and |rowTrack| should be smaller than our column / row count. for (size_t i = 0; i < columnTrack && i < columnTracks.size(); ++i) offset.setX(offset.x() + columnTracks[i].m_usedBreadth); for (size_t i = 0; i < rowTrack && i < rowTracks.size(); ++i) diff --git a/Source/WebCore/rendering/RenderGrid.h b/Source/WebCore/rendering/RenderGrid.h index e5017fae0..340c64851 100644 --- a/Source/WebCore/rendering/RenderGrid.h +++ b/Source/WebCore/rendering/RenderGrid.h @@ -50,6 +50,7 @@ private: void layoutGridItems(); LayoutPoint findChildLogicalPosition(RenderBox*, const Vector<GridTrack>& columnTracks, const Vector<GridTrack>& rowTracks); + size_t resolveGridPosition(const GridPosition&) const; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp index 2a8fe8823..4e27e6d99 100644 --- a/Source/WebCore/rendering/RenderInline.cpp +++ b/Source/WebCore/rendering/RenderInline.cpp @@ -1182,6 +1182,8 @@ const RenderObject* RenderInline::pushMappingToContainer(const RenderLayerModelO bool offsetDependsOnPoint = false; LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint); + if (geometryMap.mapCoordinatesFlags() & SnapOffsetForTransforms) + containerOffset = roundedIntSize(containerOffset); bool preserve3D = container->style()->preserves3D() || style()->preserves3D(); if (shouldUseTransformFromContainer(container)) { diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index fcd52fd15..4e67cd571 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. * * Portions are Copyright (C) 1998 Netscape Communications Corporation. * @@ -77,6 +77,7 @@ #include "PlatformMouseEvent.h" #include "RenderArena.h" #include "RenderFlowThread.h" +#include "RenderGeometryMap.h" #include "RenderInline.h" #include "RenderMarquee.h" #include "RenderReplica.h" @@ -90,6 +91,7 @@ #include "ScrollAnimator.h" #include "Scrollbar.h" #include "ScrollbarTheme.h" +#include "ScrollingCoordinator.h" #include "Settings.h" #include "SourceGraphic.h" #include "StylePropertySet.h" @@ -261,7 +263,8 @@ RenderLayer::~RenderLayer() #if USE(ACCELERATED_COMPOSITING) RenderLayerCompositor* RenderLayer::compositor() const { - ASSERT(renderer()->view()); + if (!renderer()->view()) + return 0; return renderer()->view()->compositor(); } @@ -334,55 +337,34 @@ LayoutPoint RenderLayer::computeOffsetFromRoot(bool& hasLayerOffset) const return offset; } -void RenderLayer::updateLayerPositions(LayoutPoint* offsetFromRoot, UpdateLayerPositionsFlags flags) +void RenderLayer::updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags flags) { -#if !ASSERT_DISABLED - if (offsetFromRoot) { - bool hasLayerOffset; - LayoutPoint computedOffsetFromRoot = computeOffsetFromRoot(hasLayerOffset); - ASSERT(hasLayerOffset); - ASSERT(*offsetFromRoot == computedOffsetFromRoot); - } -#endif + RenderGeometryMap geometryMap(UseTransforms); + if (this != rootLayer) + geometryMap.pushMappingsToAncestor(parent(), 0); + updateLayerPositions(&geometryMap, flags); +} +void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLayerPositionsFlags flags) +{ updateLayerPosition(); // For relpositioned layers or non-positioned layers, // we need to keep in sync, since we may have shifted relative // to our parent layer. - LayoutPoint oldOffsetFromRoot; - if (offsetFromRoot) { - // We can't cache our offset to the repaint container if the mapping is anything more complex than a simple translation - if (!canUseConvertToLayerCoords()) - offsetFromRoot = 0; // If our cached offset is invalid make sure it's not passed to any of our children + if (geometryMap) + geometryMap->pushMappingsToAncestor(this, parent()); + + if (hasOverflowControls()) { + LayoutPoint offsetFromRoot; + if (geometryMap) + offsetFromRoot = LayoutPoint(geometryMap->absolutePoint(FloatPoint())); else { - oldOffsetFromRoot = *offsetFromRoot; - // Frequently our parent layer's renderer will be the same as our renderer's containing block. In that case, - // we just update the cache using our offset to our parent (which is m_topLeft). Otherwise, regenerated cached - // offsets to the root from the render tree. - if (!m_parent || m_parent->renderer() == renderer()->containingBlock()) - offsetFromRoot->move(m_topLeft.x(), m_topLeft.y()); // Fast case - else { - LayoutPoint offset; - convertToLayerCoords(root(), offset); - *offsetFromRoot = offset; - } + // FIXME: It looks suspicious to call convertToLayerCoords here + // as canUseConvertToLayerCoords may be true for an ancestor layer. + convertToLayerCoords(root(), offsetFromRoot); } + positionOverflowControls(toSize(roundedIntPoint(offsetFromRoot))); } - LayoutPoint offset; - if (offsetFromRoot) { - offset = *offsetFromRoot; -#ifndef NDEBUG - LayoutPoint computedOffsetFromRoot; - convertToLayerCoords(root(), computedOffsetFromRoot); - ASSERT(offset == computedOffsetFromRoot); -#endif - } else { - // FIXME: It looks suspicious to call convertToLayerCoords here - // as canUseConvertToLayerCoords may be true for an ancestor layer. - convertToLayerCoords(root(), offset); - } - positionOverflowControls(toSize(roundedIntPoint(offset))); - updateDescendantDependentFlags(); if (flags & UpdatePagination) @@ -401,7 +383,8 @@ void RenderLayer::updateLayerPositions(LayoutPoint* offsetFromRoot, UpdateLayerP RenderLayerModelObject* repaintContainer = renderer()->containerForRepaint(); LayoutRect oldRepaintRect = m_repaintRect; LayoutRect oldOutlineBox = m_outlineBox; - computeRepaintRects(offsetFromRoot); + computeRepaintRects(repaintContainer, geometryMap); + // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048 if (flags & CheckForRepaint) { @@ -434,7 +417,7 @@ void RenderLayer::updateLayerPositions(LayoutPoint* offsetFromRoot, UpdateLayerP flags |= UpdatePagination; for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->updateLayerPositions(offsetFromRoot, flags); + child->updateLayerPositions(geometryMap, flags); #if USE(ACCELERATED_COMPOSITING) if ((flags & UpdateCompositingLayers) && isComposited()) @@ -450,8 +433,8 @@ void RenderLayer::updateLayerPositions(LayoutPoint* offsetFromRoot, UpdateLayerP m_updatingMarqueePosition = oldUpdatingMarqueePosition; } - if (offsetFromRoot) - *offsetFromRoot = oldOffsetFromRoot; + if (geometryMap) + geometryMap->popMappingsToAncestor(parent()); } LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const @@ -491,13 +474,12 @@ void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus() } } -void RenderLayer::computeRepaintRects(LayoutPoint* offsetFromRoot) +void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap) { ASSERT(!m_visibleContentStatusDirty); - RenderLayerModelObject* repaintContainer = renderer()->containerForRepaint(); m_repaintRect = renderer()->clippedOverflowRectForRepaint(repaintContainer); - m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer, offsetFromRoot); + m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer, geometryMap); } @@ -505,7 +487,8 @@ void RenderLayer::computeRepaintRectsIncludingDescendants() { // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects. // We should make this more efficient. - computeRepaintRects(); + // FIXME: it's wrong to call this when layout is not up-to-date, which we do. + computeRepaintRects(renderer()->containerForRepaint()); for (RenderLayer* layer = firstChild(); layer; layer = layer->nextSibling()) layer->computeRepaintRectsIncludingDescendants(); @@ -520,7 +503,16 @@ void RenderLayer::clearRepaintRects() m_outlineBox = IntRect(); } -void RenderLayer::updateLayerPositionsAfterScroll(UpdateLayerPositionsAfterScrollFlags flags) +void RenderLayer::updateLayerPositionsAfterScroll() +{ + RenderGeometryMap geometryMap(UseTransforms); + RenderView* view = renderer()->view(); + if (this != view->layer()) + geometryMap.pushMappingsToAncestor(parent(), 0); + updateLayerPositionsAfterScroll(&geometryMap); +} + +void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, UpdateLayerPositionsAfterScrollFlags flags) { // FIXME: This shouldn't be needed, but there are some corner cases where // these flags are still dirty. Update so that the check below is valid. @@ -534,21 +526,25 @@ void RenderLayer::updateLayerPositionsAfterScroll(UpdateLayerPositionsAfterScrol updateLayerPosition(); + if (geometryMap) + geometryMap->pushMappingsToAncestor(this, parent()); + if ((flags & HasSeenViewportConstrainedAncestor) || renderer()->style()->hasViewportConstrainedPosition()) { // FIXME: Is it worth passing the offsetFromRoot around like in updateLayerPositions? - computeRepaintRects(); + // FIXME: We could track the repaint container as we walk down the tree. + computeRepaintRects(renderer()->containerForRepaint(), geometryMap); flags |= HasSeenViewportConstrainedAncestor; } else if ((flags & HasSeenAncestorWithOverflowClip) && !m_canSkipRepaintRectsUpdateOnScroll) { // If we have seen an overflow clip, we should update our repaint rects as clippedOverflowRectForRepaint // intersects it with our ancestor overflow clip that may have moved. - computeRepaintRects(); + computeRepaintRects(renderer()->containerForRepaint(), geometryMap); } if (renderer()->hasOverflowClip()) flags |= HasSeenAncestorWithOverflowClip; for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->updateLayerPositionsAfterScroll(flags); + child->updateLayerPositionsAfterScroll(geometryMap, flags); // We don't update our reflection as scrolling is a translation which does not change the size() // of an object, thus RenderReplica will still repaint itself properly as the layer position was @@ -560,6 +556,9 @@ void RenderLayer::updateLayerPositionsAfterScroll(UpdateLayerPositionsAfterScrol m_marquee->updateMarqueePosition(); m_updatingMarqueePosition = oldUpdatingMarqueePosition; } + + if (geometryMap) + geometryMap->popMappingsToAncestor(parent()); } #if ENABLE(CSS_COMPOSITING) @@ -702,7 +701,7 @@ void RenderLayer::setHasVisibleContent() m_visibleContentStatusDirty = false; m_hasVisibleContent = true; - computeRepaintRects(); + computeRepaintRects(renderer()->containerForRepaint()); if (!isNormalFlowOnly()) { // We don't collect invisible layers in z-order lists if we are not in compositing mode. // As we became visible, we need to dirty our stacking contexts ancestors to be properly @@ -848,7 +847,7 @@ void RenderLayer::updateLayerPosition() { LayoutPoint localPoint; LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done. - if (renderer()->isRenderInline()) { + if (renderer()->isInline() && renderer()->isRenderInline()) { RenderInline* inlineFlow = toRenderInline(renderer()); IntRect lineBox = inlineFlow->linesBoundingBox(); setSize(lineBox.size()); @@ -1114,7 +1113,7 @@ void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect, // If we have at least one custom shader, we need to update the whole bounding box of the layer, because the // shader can address any ouput pixel. // Note: This is only for output rect, so there's no need to expand the dirty source rect. - rectForRepaint.unite(calculateLayerBounds(this, this)); + rectForRepaint.unite(calculateLayerBounds(this)); } #endif @@ -1423,8 +1422,6 @@ void RenderLayer::removeOnlyThisLayer() clearClipRectsIncludingDescendants(); RenderLayer* nextSib = nextSibling(); - bool hasLayerOffset; - const LayoutPoint offsetFromRootBeforeMove = computeOffsetFromRoot(hasLayerOffset); // Remove the child reflection layer before moving other child layers. // The reflection layer should not be moved to the parent. @@ -1438,10 +1435,9 @@ void RenderLayer::removeOnlyThisLayer() removeChild(current); m_parent->addChild(current, nextSib); current->setRepaintStatus(NeedsFullRepaint); - LayoutPoint offsetFromRoot = offsetFromRootBeforeMove; // updateLayerPositions depends on hasLayer() already being false for proper layout. ASSERT(!renderer()->hasLayer()); - current->updateLayerPositions(hasLayerOffset ? &offsetFromRoot : 0); + current->updateLayerPositions(0); // FIXME: use geometry map. current = next; } @@ -1483,36 +1479,37 @@ void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLa roundedRect = pixelSnappedIntRect(rect); } -void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location) const +// Returns the layer reached on the walk up towards the ancestor. +static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location) { - if (ancestorLayer == this) - return; + ASSERT(ancestorLayer != layer); - EPosition position = renderer()->style()->position(); + const RenderLayerModelObject* renderer = layer->renderer(); + EPosition position = renderer->style()->position(); // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread // may need to be revisited in a future patch. // If the fixed renderer is inside a RenderFlowThread, we should not compute location using localToAbsolute, // since localToAbsolute maps the coordinates from named flow to regions coordinates and regions can be // positioned in a completely different place in the viewport (RenderView). - if (position == FixedPosition && !renderer()->inRenderFlowThread() && (!ancestorLayer || ancestorLayer == renderer()->view()->layer())) { + if (position == FixedPosition && !renderer->inRenderFlowThread() && (!ancestorLayer || ancestorLayer == renderer->view()->layer())) { // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling // localToAbsolute() on the RenderView. - FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), IsFixed); + FloatPoint absPos = renderer->localToAbsolute(FloatPoint(), IsFixed); location += LayoutSize(absPos.x(), absPos.y()); - return; + return ancestorLayer; } // For the fixed positioned elements inside a render flow thread, we should also skip the code path below // Otherwise, for the case of ancestorLayer == rootLayer and fixed positioned element child of a transformed // element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer. - if (position == FixedPosition && !renderer()->inRenderFlowThread()) { + if (position == FixedPosition && !renderer->inRenderFlowThread()) { // For a fixed layers, we need to walk up to the root to see if there's a fixed position container // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform, // so we should always find the ancestor at or before we find the fixed position container. RenderLayer* fixedPositionContainerLayer = 0; bool foundAncestor = false; - for (RenderLayer* currLayer = parent(); currLayer; currLayer = currLayer->parent()) { + for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = currLayer->parent()) { if (currLayer == ancestorLayer) foundAncestor = true; @@ -1527,20 +1524,20 @@ void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutP if (fixedPositionContainerLayer != ancestorLayer) { LayoutPoint fixedContainerCoords; - convertToLayerCoords(fixedPositionContainerLayer, fixedContainerCoords); + layer->convertToLayerCoords(fixedPositionContainerLayer, fixedContainerCoords); LayoutPoint ancestorCoords; ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorCoords); location += (fixedContainerCoords - ancestorCoords); - return; + return ancestorLayer; } } RenderLayer* parentLayer; if (position == AbsolutePosition || position == FixedPosition) { // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way. - parentLayer = parent(); + parentLayer = layer->parent(); bool foundAncestorFirst = false; while (parentLayer) { // RenderFlowThread is a positioned container, child of RenderView, positioned at (0,0). @@ -1559,8 +1556,8 @@ void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutP // We should not reach RenderView layer past the RenderFlowThread layer for any // children of the RenderFlowThread. - if (renderer()->inRenderFlowThread() && !renderer()->isRenderFlowThread()) - ASSERT(parentLayer != renderer()->view()->layer()); + if (renderer->inRenderFlowThread() && !renderer->isRenderFlowThread()) + ASSERT(parentLayer != renderer->view()->layer()); if (foundAncestorFirst) { // Found ancestorLayer before the abs. positioned container, so compute offset of both relative @@ -1568,23 +1565,32 @@ void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutP RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor(); LayoutPoint thisCoords; - convertToLayerCoords(positionedAncestor, thisCoords); + layer->convertToLayerCoords(positionedAncestor, thisCoords); LayoutPoint ancestorCoords; ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorCoords); location += (thisCoords - ancestorCoords); - return; + return ancestorLayer; } } else - parentLayer = parent(); + parentLayer = layer->parent(); if (!parentLayer) - return; + return 0; - parentLayer->convertToLayerCoords(ancestorLayer, location); + location += toSize(layer->location()); + return parentLayer; +} - location += toSize(m_topLeft); +void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location) const +{ + if (ancestorLayer == this) + return; + + const RenderLayer* currLayer = this; + while (currLayer && currLayer != ancestorLayer) + currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, location); } void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect& rect) const @@ -1729,29 +1735,32 @@ void RenderLayer::scrollTo(int x, int y) Frame* frame = renderer()->frame(); InspectorInstrumentation::willScrollLayer(frame); - // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll). - // We don't update compositing layers, because we need to do a deep update from the compositing ancestor. - updateLayerPositionsAfterScroll(); - RenderView* view = renderer()->view(); // We should have a RenderView if we're trying to scroll. ASSERT(view); - if (view) { - // Update regions, scrolling may change the clip of a particular region. + + // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll). + // We don't update compositing layers, because we need to do a deep update from the compositing ancestor. + bool inLayout = view ? view->frameView()->isInLayout() : false; + if (!inLayout) { + // If we're in the middle of layout, we'll just update layers once layout has finished. + updateLayerPositionsAfterScroll(); + if (view) { + // Update regions, scrolling may change the clip of a particular region. #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION) - view->frameView()->updateAnnotatedRegions(); + view->frameView()->updateAnnotatedRegions(); #endif + view->updateWidgetPositions(); + } - view->updateWidgetPositions(); - } - - if (!m_updatingMarqueePosition) { - // Avoid updating compositing layers if, higher on the stack, we're already updating layer - // positions. Updating layer positions requires a full walk of up-to-date RenderLayers, and - // in this case we're still updating their positions; we'll update compositing layers later - // when that completes. - updateCompositingLayersAfterScroll(); + if (!m_updatingMarqueePosition) { + // Avoid updating compositing layers if, higher on the stack, we're already updating layer + // positions. Updating layer positions requires a full walk of up-to-date RenderLayers, and + // in this case we're still updating their positions; we'll update compositing layers later + // when that completes. + updateCompositingLayersAfterScroll(); + } } RenderLayerModelObject* repaintContainer = renderer()->containerForRepaint(); @@ -1885,27 +1894,10 @@ void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignm frameView->resumeScheduledEvents(); } -#if USE(ACCELERATED_COMPOSITING) -static FrameView* frameViewFromLayer(const RenderLayer* layer) -{ - Frame* frame = layer->renderer()->frame(); - if (!frame) - return 0; - - return frame->view(); -} -#endif - void RenderLayer::updateCompositingLayersAfterScroll() { #if USE(ACCELERATED_COMPOSITING) if (compositor()->inCompositingMode()) { - // If we're in the middle of layout, we'll just update compositiong once layout has finished. - if (FrameView* frameView = frameViewFromLayer(this)) { - if (frameView->isInLayout()) - return; - } - // Our stacking context is guaranteed to contain all of our descendants that may need // repositioning, so update compositing layers from there. if (RenderLayer* compositingAncestor = stackingContext()->enclosingCompositingLayer()) { @@ -2291,6 +2283,34 @@ IntPoint RenderLayer::currentMousePosition() const return renderer()->frame() ? renderer()->frame()->eventHandler()->currentMousePosition() : IntPoint(); } +IntRect RenderLayer::rectForHorizontalScrollbar(const IntRect& borderBoxRect) const +{ + if (!m_hBar) + return IntRect(); + + const RenderBox* box = renderBox(); + const IntRect& scrollCorner = scrollCornerRect(); + + return IntRect(horizontalScrollbarStart(borderBoxRect.x()), + borderBoxRect.maxY() - box->borderBottom() - m_hBar->height(), + borderBoxRect.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(), + m_hBar->height()); +} + +IntRect RenderLayer::rectForVerticalScrollbar(const IntRect& borderBoxRect) const +{ + if (!m_vBar) + return IntRect(); + + const RenderBox* box = renderBox(); + const IntRect& scrollCorner = scrollCornerRect(); + + return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()), + borderBoxRect.y() + box->borderTop(), + m_vBar->width(), + borderBoxRect.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height()); +} + LayoutUnit RenderLayer::verticalScrollbarStart(int minX, int maxX) const { const RenderBox* box = renderBox(); @@ -2513,18 +2533,18 @@ void RenderLayer::positionOverflowControls(const IntSize& offsetFromRoot) const IntRect borderBox = box->pixelSnappedBorderBoxRect(); const IntRect& scrollCorner = scrollCornerRect(); IntRect absBounds(borderBox.location() + offsetFromRoot, borderBox.size()); - if (m_vBar) - m_vBar->setFrameRect(IntRect(verticalScrollbarStart(absBounds.x(), absBounds.maxX()), - absBounds.y() + box->borderTop(), - m_vBar->width(), - absBounds.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height())); - - if (m_hBar) - m_hBar->setFrameRect(IntRect(horizontalScrollbarStart(absBounds.x()), - absBounds.maxY() - box->borderBottom() - m_hBar->height(), - absBounds.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(), - m_hBar->height())); - + if (m_vBar) { + IntRect vBarRect = rectForVerticalScrollbar(borderBox); + vBarRect.move(offsetFromRoot); + m_vBar->setFrameRect(vBarRect); + } + + if (m_hBar) { + IntRect hBarRect = rectForHorizontalScrollbar(borderBox); + hBarRect.move(offsetFromRoot); + m_hBar->setFrameRect(hBarRect); + } + if (m_scrollCorner) m_scrollCorner->setFrameRect(scrollCorner); if (m_resizer) @@ -2715,6 +2735,25 @@ void RenderLayer::updateScrollInfoAfterLayout() #endif } +bool RenderLayer::overflowControlsIntersectRect(const IntRect& localRect) const +{ + const IntRect borderBox = renderBox()->pixelSnappedBorderBoxRect(); + + if (rectForHorizontalScrollbar(borderBox).intersects(localRect)) + return true; + + if (rectForVerticalScrollbar(borderBox).intersects(localRect)) + return true; + + if (scrollCornerRect().intersects(localRect)) + return true; + + if (resizerCornerRect(this, borderBox).intersects(localRect)) + return true; + + return false; +} + void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls) { // Don't do anything if we have no overflow. @@ -2734,9 +2773,21 @@ void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint if ((m_hBar && layerForHorizontalScrollbar()) || (m_vBar && layerForVerticalScrollbar())) return; #endif + IntRect localDamgeRect = damageRect; + localDamgeRect.moveBy(-paintOffset); + if (!overflowControlsIntersectRect(localDamgeRect)) + return; + RenderView* renderView = renderer()->view(); - renderView->layer()->setContainsDirtyOverlayScrollbars(true); - renderView->frameView()->setContainsScrollableAreaWithOverlayScrollbars(true); + + RenderLayer* paintingRoot = 0; +#if USE(ACCELERATED_COMPOSITING) + paintingRoot = enclosingCompositingLayer(); +#endif + if (!paintingRoot) + paintingRoot = renderView->layer(); + + paintingRoot->setContainsDirtyOverlayScrollbars(true); return; } @@ -2939,7 +2990,10 @@ bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularit void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot, RenderRegion* region, PaintLayerFlags paintFlags) { OverlapTestRequestMap overlapTestRequests; - paintLayer(this, context, enclosingIntRect(damageRect), LayoutSize(), paintBehavior, paintingRoot, region, &overlapTestRequests, paintFlags); + + LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot, region, &overlapTestRequests); + paintLayer(context, paintingInfo, paintFlags); + OverlapTestRequestMap::iterator end = overlapTestRequests.end(); for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) it->key->setOverlapTestResult(false); @@ -2949,8 +3003,10 @@ void RenderLayer::paintOverlayScrollbars(GraphicsContext* context, const LayoutR { if (!m_containsDirtyOverlayScrollbars) return; - paintLayer(this, context, damageRect, LayoutSize(), paintBehavior, paintingRoot, 0, 0, PaintLayerHaveTransparency | PaintLayerTemporaryClipRects - | PaintLayerPaintingOverlayScrollbars); + + LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot); + paintLayer(context, paintingInfo, PaintLayerPaintingOverlayScrollbars); + m_containsDirtyOverlayScrollbars = false; } @@ -3045,18 +3101,17 @@ static inline bool shouldSuppressPaintingLayer(RenderLayer* layer) } -void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* context, - const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior, - RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests, - PaintLayerFlags paintFlags) +void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) { #if USE(ACCELERATED_COMPOSITING) if (isComposited()) { // The updatingControlTints() painting pass goes through compositing layers, // but we need to ensure that we don't cache clip rects computed with the wrong root in this case. - if (context->updatingControlTints() || (paintBehavior & PaintBehaviorFlattenCompositingLayers)) + if (context->updatingControlTints() || (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers)) paintFlags |= PaintLayerTemporaryClipRects; - else if (!backing()->paintsIntoWindow() && !backing()->paintsIntoCompositedAncestor() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection) && !(rootLayer->containsDirtyOverlayScrollbars() && (paintFlags & PaintLayerPaintingOverlayScrollbars))) { + else if (!backing()->paintsIntoWindow() + && !backing()->paintsIntoCompositedAncestor() + && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) { // If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer(). return; } @@ -3074,12 +3129,12 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* context, if (!renderer()->opacity()) return; - if (paintsWithTransparency(paintBehavior)) + if (paintsWithTransparency(paintingInfo.paintBehavior)) paintFlags |= PaintLayerHaveTransparency; // PaintLayerAppliedTransform is used in RenderReplica, to avoid applying the transform twice. - if (paintsWithTransform(paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) { - TransformationMatrix layerTransform = renderableTransform(paintBehavior); + if (paintsWithTransform(paintingInfo.paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) { + TransformationMatrix layerTransform = renderableTransform(paintingInfo.paintBehavior); // If the transform can't be inverted, then don't paint anything. if (!layerTransform.isInvertible()) return; @@ -3088,31 +3143,32 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* context, // layer from the parent now, assuming there is a parent if (paintFlags & PaintLayerHaveTransparency) { if (parent()) - parent()->beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior); + parent()->beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior); else - beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior); + beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior); } // Make sure the parent's clip rects have been calculated. - ClipRect clipRect = paintDirtyRect; + ClipRect clipRect = paintingInfo.paintDirtyRect; if (parent()) { - clipRect = backgroundClipRect(rootLayer, region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, + ClipRectsContext clipRectsContext(paintingInfo.rootLayer, paintingInfo.region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip); - clipRect.intersect(paintDirtyRect); + clipRect = backgroundClipRect(clipRectsContext); + clipRect.intersect(paintingInfo.paintDirtyRect); // Push the parent coordinate space's clip. - parent()->clipToRect(rootLayer, context, paintDirtyRect, clipRect); + parent()->clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, clipRect); } // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space. // This involves subtracting out the position of the layer in our current coordinate space, but preserving // the accumulated error for sub-pixel layout. LayoutPoint delta; - convertToLayerCoords(rootLayer, delta); + convertToLayerCoords(paintingInfo.rootLayer, delta); TransformationMatrix transform(layerTransform); IntPoint roundedDelta = roundedIntPoint(delta); transform.translateRight(roundedDelta.x(), roundedDelta.y()); - LayoutSize adjustedSubPixelAccumulation = subPixelAccumulation + (delta - roundedDelta); + LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta); // Apply the transform. { @@ -3120,23 +3176,21 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* context, context->concatCTM(transform.toAffineTransform()); // Now do a paint with the root layer shifted to be us. - paintLayerContentsAndReflection(this, context, enclosingIntRect(transform.inverse().mapRect(paintDirtyRect)), adjustedSubPixelAccumulation, paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags); + LayerPaintingInfo transformedPaintingInfo(this, enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect)), paintingInfo.paintBehavior, adjustedSubPixelAccumulation, paintingInfo.paintingRoot, paintingInfo.region, paintingInfo.overlapTestRequests); + paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags); } // Restore the clip. if (parent()) - parent()->restoreClip(context, paintDirtyRect, clipRect); + parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect); return; } - paintLayerContentsAndReflection(rootLayer, context, paintDirtyRect, subPixelAccumulation, paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags); + paintLayerContentsAndReflection(context, paintingInfo, paintFlags); } -void RenderLayer::paintLayerContentsAndReflection(RenderLayer* rootLayer, GraphicsContext* context, - const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior, - RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests, - PaintLayerFlags paintFlags) +void RenderLayer::paintLayerContentsAndReflection(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) { ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); @@ -3146,18 +3200,15 @@ void RenderLayer::paintLayerContentsAndReflection(RenderLayer* rootLayer, Graphi if (m_reflection && !m_paintingInsideReflection) { // Mark that we are now inside replica painting. m_paintingInsideReflection = true; - reflectionLayer()->paintLayer(rootLayer, context, paintDirtyRect, subPixelAccumulation, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags | PaintLayerPaintingReflection); + reflectionLayer()->paintLayer(context, paintingInfo, localPaintFlags | PaintLayerPaintingReflection); m_paintingInsideReflection = false; } localPaintFlags |= PaintLayerPaintingCompositingAllPhases; - paintLayerContents(rootLayer, context, paintDirtyRect, subPixelAccumulation, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags); + paintLayerContents(context, paintingInfo, localPaintFlags); } -void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* context, - const LayoutRect& parentPaintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior, - RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests, - PaintLayerFlags paintFlags) +void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) { ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); @@ -3169,18 +3220,38 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co bool shouldPaintOutline = isSelfPaintingLayer && !isPaintingOverlayScrollbars; bool shouldPaintContent = m_hasVisibleContent && isSelfPaintingLayer && !isPaintingOverlayScrollbars; - // Calculate the clip rects we should use only when we need them. - LayoutRect layerBounds; - ClipRect damageRect, clipRectToApply, outlineRect; - LayoutPoint paintOffset; - LayoutRect paintDirtyRect = parentPaintDirtyRect; - bool useClipRect = true; GraphicsContext* transparencyLayerContext = context; // Ensure our lists are up-to-date. updateLayerListsIfNeeded(); + LayoutPoint offsetFromRoot; + convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot); + + IntRect rootRelativeBounds; + bool rootRelativeBoundsComputed = false; + + bool didQuantizeFonts = true; + bool scrollingOnMainThread = true; + Frame* frame = renderer()->frame(); +#if ENABLE(THREADED_SCROLLING) + if (frame) { + if (Page* page = frame->page()) { + if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) + scrollingOnMainThread = scrollingCoordinator->shouldUpdateScrollLayerPositionOnMainThread(); + } + } +#endif + + // FIXME: We shouldn't have to disable subpixel quantization for overflow clips or subframes once we scroll those + // things on the scrolling thread. + bool needToAdjustSubpixelQuantization = scrollingOnMainThread || (renderer()->hasOverflowClip() && !usesCompositedScrolling()) || (frame && frame->ownerElement()); + if (needToAdjustSubpixelQuantization) { + didQuantizeFonts = context->shouldSubpixelQuantizeFonts(); + context->setShouldSubpixelQuantizeFonts(false); + } + // Apply clip-path to context. bool hasClipPath = false; RenderStyle* style = renderer()->style(); @@ -3190,7 +3261,13 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co hasClipPath = true; context->save(); ShapeClipPathOperation* clipPath = static_cast<ShapeClipPathOperation*>(style->clipPath()); - context->clipPath(clipPath->path(calculateLayerBounds(this, rootLayer, 0)), clipPath->windRule()); + + if (!rootRelativeBoundsComputed) { + rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); + rootRelativeBoundsComputed = true; + } + + context->clipPath(clipPath->path(rootRelativeBounds), clipPath->windRule()); } #if ENABLE(SVG) else if (style->clipPath()->getOperationType() == ClipPathOperation::REFERENCE) { @@ -3198,22 +3275,33 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co Document* document = renderer()->document(); // FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405) Element* element = document ? document->getElementById(referenceClipPathOperation->fragment()) : 0; - if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) - static_cast<RenderSVGResourceClipper*>(element->renderer())->applyClippingToContext(renderer(), calculateLayerBounds(this, rootLayer, 0), paintDirtyRect, context); + if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) { + if (!rootRelativeBoundsComputed) { + rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); + rootRelativeBoundsComputed = true; + } + + static_cast<RenderSVGResourceClipper*>(element->renderer())->applyClippingToContext(renderer(), rootRelativeBounds, paintingInfo.paintDirtyRect, context); + } } #endif } + LayerPaintingInfo localPaintingInfo(paintingInfo); #if ENABLE(CSS_FILTERS) FilterEffectRendererHelper filterPainter(filterRenderer() && paintsWithFilters()); if (filterPainter.haveFilterEffect() && !context->paintingDisabled()) { - LayoutPoint rootLayerOffset; - convertToLayerCoords(rootLayer, rootLayerOffset); RenderLayerFilterInfo* filterInfo = this->filterInfo(); ASSERT(filterInfo); LayoutRect filterRepaintRect = filterInfo->dirtySourceRect(); - filterRepaintRect.move(rootLayerOffset.x(), rootLayerOffset.y()); - if (filterPainter.prepareFilterEffect(this, calculateLayerBounds(this, rootLayer, 0), parentPaintDirtyRect, filterRepaintRect)) { + filterRepaintRect.move(offsetFromRoot.x(), offsetFromRoot.y()); + + if (!rootRelativeBoundsComputed) { + rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); + rootRelativeBoundsComputed = true; + } + + if (filterPainter.prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect, filterRepaintRect)) { // Now we know for sure, that the source image will be updated, so we can revert our tracking repaint rect back to zero. filterInfo->resetDirtySourceRect(); @@ -3225,7 +3313,7 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co // Check that we didn't fail to allocate the graphics context for the offscreen buffer. if (filterPainter.hasStartedFilterEffect()) { - paintDirtyRect = filterPainter.repaintRect(); + localPaintingInfo.paintDirtyRect = filterPainter.repaintRect(); // If the filter needs the full source image, we need to avoid using the clip rectangles. // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly. // Note that we will still apply the clipping on the final rendering of the filter. @@ -3234,57 +3322,62 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co } } #endif - + + // Calculate the clip rects we should use only when we need them. + LayoutRect layerBounds; + ClipRect damageRect, clipRectToApply, outlineRect; + LayoutPoint paintOffset; + if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) { - calculateRects(rootLayer, region, (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, - IgnoreOverlayScrollbarSize, localPaintFlags & PaintLayerPaintingOverflowContents ? IgnoreOverflowClip : RespectOverflowClip); - paintOffset = toPoint(layerBounds.location() - renderBoxLocation() + subPixelAccumulation); - if (this == rootLayer) + ClipRectsContext clipRectsContext(localPaintingInfo.rootLayer, localPaintingInfo.region, (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize, localPaintFlags & PaintLayerPaintingOverflowContents ? IgnoreOverflowClip : RespectOverflowClip); + calculateRects(clipRectsContext, localPaintingInfo.paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, &offsetFromRoot); + paintOffset = toPoint(layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation); + if (this == localPaintingInfo.rootLayer) paintOffset = roundedIntPoint(paintOffset); } - bool forceBlackText = paintBehavior & PaintBehaviorForceBlackText; - bool selectionOnly = paintBehavior & PaintBehaviorSelectionOnly; + bool forceBlackText = localPaintingInfo.paintBehavior & PaintBehaviorForceBlackText; + bool selectionOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionOnly; // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set). // Else, our renderer tree may or may not contain the painting root, so we pass that root along // so it will be tested against as we descend through the renderers. RenderObject* paintingRootForRenderer = 0; - if (paintingRoot && !renderer()->isDescendantOf(paintingRoot)) - paintingRootForRenderer = paintingRoot; + if (localPaintingInfo.paintingRoot && !renderer()->isDescendantOf(localPaintingInfo.paintingRoot)) + paintingRootForRenderer = localPaintingInfo.paintingRoot; - if (overlapTestRequests && isSelfPaintingLayer) - performOverlapTests(*overlapTestRequests, rootLayer, this); + if (localPaintingInfo.overlapTestRequests && isSelfPaintingLayer) + performOverlapTests(*localPaintingInfo.overlapTestRequests, localPaintingInfo.rootLayer, this); // We want to paint our layer, but only if we intersect the damage rect. - if (this != rootLayer || !(localPaintFlags & PaintLayerPaintingOverflowContents)) - shouldPaintContent &= intersectsDamageRect(layerBounds, damageRect.rect(), rootLayer); + if (this != localPaintingInfo.rootLayer || !(localPaintFlags & PaintLayerPaintingOverflowContents)) + shouldPaintContent &= intersectsDamageRect(layerBounds, damageRect.rect(), localPaintingInfo.rootLayer, &offsetFromRoot); if (localPaintFlags & PaintLayerPaintingCompositingBackgroundPhase) { if (shouldPaintContent && !selectionOnly) { // Begin transparency layers lazily now that we know we have to paint something. if (haveTransparency) - beginTransparencyLayers(transparencyLayerContext, rootLayer, paintDirtyRect, paintBehavior); + beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior); if (useClipRect) { // Paint our background first, before painting any child layers. // Establish the clip used to paint our background. - clipToRect(rootLayer, context, paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self. + clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self. } // Paint the background. - PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseBlockBackground, false, paintingRootForRenderer, region, 0); + PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseBlockBackground, false, paintingRootForRenderer, localPaintingInfo.region, 0); renderer()->paint(paintInfo, paintOffset); if (useClipRect) { // Restore the clip. - restoreClip(context, paintDirtyRect, damageRect); + restoreClip(context, localPaintingInfo.paintDirtyRect, damageRect); } } // Now walk the sorted list of children with negative z-indices. - paintList(negZOrderList(), rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags); + paintList(negZOrderList(), context, localPaintingInfo, localPaintFlags); } if (localPaintFlags & PaintLayerPaintingCompositingForegroundPhase) { @@ -3292,22 +3385,22 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co if (shouldPaintContent && !clipRectToApply.isEmpty()) { // Begin transparency layers lazily now that we know we have to paint something. if (haveTransparency) - beginTransparencyLayers(transparencyLayerContext, rootLayer, paintDirtyRect, paintBehavior); + beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior); if (useClipRect) { // Set up the clip used when painting our children. - clipToRect(rootLayer, context, paintDirtyRect, clipRectToApply); + clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, clipRectToApply); } PaintInfo paintInfo(context, pixelSnappedIntRect(clipRectToApply.rect()), selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds, - forceBlackText, paintingRootForRenderer, region, 0); + forceBlackText, paintingRootForRenderer, localPaintingInfo.region, 0); renderer()->paint(paintInfo, paintOffset); if (!selectionOnly) { paintInfo.phase = PaintPhaseFloat; renderer()->paint(paintInfo, paintOffset); paintInfo.phase = PaintPhaseForeground; - paintInfo.overlapTestRequests = overlapTestRequests; + paintInfo.overlapTestRequests = localPaintingInfo.overlapTestRequests; renderer()->paint(paintInfo, paintOffset); paintInfo.phase = PaintPhaseChildOutlines; renderer()->paint(paintInfo, paintOffset); @@ -3315,37 +3408,37 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co if (useClipRect) { // Now restore our clip. - restoreClip(context, paintDirtyRect, clipRectToApply); + restoreClip(context, localPaintingInfo.paintDirtyRect, clipRectToApply); } } if (shouldPaintOutline && !outlineRect.isEmpty()) { // Paint our own outline - PaintInfo paintInfo(context, pixelSnappedIntRect(outlineRect.rect()), PaintPhaseSelfOutline, false, paintingRootForRenderer, region, 0); - clipToRect(rootLayer, context, paintDirtyRect, outlineRect, DoNotIncludeSelfForBorderRadius); + PaintInfo paintInfo(context, pixelSnappedIntRect(outlineRect.rect()), PaintPhaseSelfOutline, false, paintingRootForRenderer, localPaintingInfo.region, 0); + clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, outlineRect, DoNotIncludeSelfForBorderRadius); renderer()->paint(paintInfo, paintOffset); - restoreClip(context, paintDirtyRect, outlineRect); + restoreClip(context, localPaintingInfo.paintDirtyRect, outlineRect); } // Paint any child layers that have overflow. - paintList(m_normalFlowList, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags); + paintList(m_normalFlowList, context, localPaintingInfo, localPaintFlags); // Now walk the sorted list of children with positive z-indices. - paintList(posZOrderList(), rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags); + paintList(posZOrderList(), context, localPaintingInfo, localPaintFlags); } if (isPaintingOverlayScrollbars) { - clipToRect(rootLayer, context, paintDirtyRect, damageRect); + clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, damageRect); paintOverflowControls(context, roundedIntPoint(paintOffset), pixelSnappedIntRect(damageRect.rect()), true); - restoreClip(context, paintDirtyRect, damageRect); + restoreClip(context, localPaintingInfo.paintDirtyRect, damageRect); } #if ENABLE(CSS_FILTERS) if (filterPainter.hasStartedFilterEffect()) { // Apply the correct clipping (ie. overflow: hidden). - clipToRect(rootLayer, transparencyLayerContext, paintDirtyRect, damageRect); + clipToRect(localPaintingInfo.rootLayer, transparencyLayerContext, localPaintingInfo.paintDirtyRect, damageRect); context = filterPainter.applyFilterEffect(); - restoreClip(transparencyLayerContext, paintDirtyRect, damageRect); + restoreClip(transparencyLayerContext, localPaintingInfo.paintDirtyRect, damageRect); } #endif @@ -3354,15 +3447,15 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co if ((localPaintFlags & PaintLayerPaintingCompositingMaskPhase) && shouldPaintContent && renderer()->hasMask() && !selectionOnly) { if (useClipRect) - clipToRect(rootLayer, context, paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self. + clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self. // Paint the mask. - PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseMask, false, paintingRootForRenderer, region, 0); + PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseMask, false, paintingRootForRenderer, localPaintingInfo.region, 0); renderer()->paint(paintInfo, paintOffset); if (useClipRect) { // Restore the clip. - restoreClip(context, paintDirtyRect, damageRect); + restoreClip(context, localPaintingInfo.paintDirtyRect, damageRect); } } @@ -3373,14 +3466,15 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co m_usedTransparency = false; } + // Re-set this to whatever it was before we painted the layer. + if (needToAdjustSubpixelQuantization) + context->setShouldSubpixelQuantizeFonts(didQuantizeFonts); + if (hasClipPath) context->restore(); } -void RenderLayer::paintList(Vector<RenderLayer*>* list, RenderLayer* rootLayer, GraphicsContext* context, - const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior, - RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests, - PaintLayerFlags paintFlags) +void RenderLayer::paintList(Vector<RenderLayer*>* list, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) { if (!list) return; @@ -3395,16 +3489,13 @@ void RenderLayer::paintList(Vector<RenderLayer*>* list, RenderLayer* rootLayer, for (size_t i = 0; i < list->size(); ++i) { RenderLayer* childLayer = list->at(i); if (!childLayer->isPaginated()) - childLayer->paintLayer(rootLayer, context, paintDirtyRect, LayoutSize(), paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags); + childLayer->paintLayer(context, paintingInfo, paintFlags); else - paintPaginatedChildLayer(childLayer, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags); + paintPaginatedChildLayer(childLayer, context, paintingInfo, paintFlags); } } -void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, GraphicsContext* context, - const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior, - RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests, - PaintLayerFlags paintFlags) +void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) { // We need to do multiple passes, breaking up our child layer into strips. Vector<RenderLayer*> columnLayers; @@ -3422,13 +3513,11 @@ void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* if (!columnLayers.size()) return; - paintChildLayerIntoColumns(childLayer, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags, columnLayers, columnLayers.size() - 1); + paintChildLayerIntoColumns(childLayer, context, paintingInfo, paintFlags, columnLayers, columnLayers.size() - 1); } -void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLayer* rootLayer, GraphicsContext* context, - const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior, - RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests, - PaintLayerFlags paintFlags, const Vector<RenderLayer*>& columnLayers, size_t colIndex) +void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, + PaintLayerFlags paintFlags, const Vector<RenderLayer*>& columnLayers, size_t colIndex) { RenderBlock* columnBlock = toRenderBlock(columnLayers[colIndex]->renderer()); @@ -3439,7 +3528,7 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLaye LayoutPoint layerOffset; // FIXME: It looks suspicious to call convertToLayerCoords here // as canUseConvertToLayerCoords is true for this layer. - columnBlock->layer()->convertToLayerCoords(rootLayer, layerOffset); + columnBlock->layer()->convertToLayerCoords(paintingInfo.rootLayer, layerOffset); bool isHorizontal = columnBlock->style()->isHorizontalWritingMode(); @@ -3466,7 +3555,7 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLaye colRect.moveBy(layerOffset); - LayoutRect localDirtyRect(paintDirtyRect); + LayoutRect localDirtyRect(paintingInfo.paintDirtyRect); localDirtyRect.intersect(colRect); if (!localDirtyRect.isEmpty()) { @@ -3486,7 +3575,11 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLaye newTransform.translateRight(roundToInt(offset.width()), roundToInt(offset.height())); childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform)); - childLayer->paintLayer(rootLayer, context, localDirtyRect, LayoutSize(), paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags); + + LayerPaintingInfo localPaintingInfo(paintingInfo); + localPaintingInfo.paintDirtyRect = localDirtyRect; + childLayer->paintLayer(context, localPaintingInfo, paintFlags); + if (oldHasTransform) childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform)); else @@ -3495,7 +3588,7 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLaye // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space. // This involves subtracting out the position of the layer in our current coordinate space. LayoutPoint childOffset; - columnLayers[colIndex - 1]->convertToLayerCoords(rootLayer, childOffset); + columnLayers[colIndex - 1]->convertToLayerCoords(paintingInfo.rootLayer, childOffset); TransformationMatrix transform; transform.translateRight(roundToInt(childOffset.x() + offset.width()), roundToInt(childOffset.y() + offset.height())); @@ -3503,9 +3596,10 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLaye context->concatCTM(transform.toAffineTransform()); // Now do a paint with the root layer shifted to be the next multicol block. - paintChildLayerIntoColumns(childLayer, columnLayers[colIndex - 1], context, transform.inverse().mapRect(localDirtyRect), paintBehavior, - paintingRoot, region, overlapTestRequests, paintFlags, - columnLayers, colIndex - 1); + LayerPaintingInfo columnPaintingInfo(paintingInfo); + columnPaintingInfo.rootLayer = columnLayers[colIndex - 1]; + columnPaintingInfo.paintDirtyRect = transform.inverse().mapRect(localDirtyRect); + paintChildLayerIntoColumns(childLayer, context, columnPaintingInfo, paintFlags, columnLayers, colIndex - 1); } } @@ -3548,7 +3642,7 @@ bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation& // return ourselves. We do this so mouse events continue getting delivered after a drag has // exited the WebView, and so hit testing over a scrollbar hits the content document. if ((request.active() || request.release()) && isRootLayer()) { - renderer()->updateHitTestResult(result, toRenderView(renderer())->flipForWritingMode(result.point())); + renderer()->updateHitTestResult(result, toRenderView(renderer())->flipForWritingMode(hitTestLocation.point())); insideLayer = this; } } @@ -3573,6 +3667,23 @@ Node* RenderLayer::enclosingElement() const return 0; } +#if ENABLE(DIALOG_ELEMENT) +bool RenderLayer::isInTopLayer() const +{ + Node* node = renderer()->node(); + return node && node->isElementNode() && toElement(node)->isInTopLayer(); +} + +bool RenderLayer::isInTopLayerSubtree() const +{ + for (const RenderLayer* layer = this; layer; layer = layer->parent()) { + if (layer->isInTopLayer()) + return true; + } + return false; +} +#endif + // Compute the z-offset of the point in the transformState. // This is effectively projecting a ray normal to the plane of ancestor, finding where that // ray intersects target, and computing the z delta between those two points. @@ -3661,13 +3772,12 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate. - bool useTemporaryClipRects = renderer()->view()->frameView()->containsScrollableAreaWithOverlayScrollbars(); - // Apply a transform if we have one. if (transform() && !appliedTransform) { // Make sure the parent's clip rects have been calculated. if (parent()) { - ClipRect clipRect = backgroundClipRect(rootLayer, hitTestLocation.region(), useTemporaryClipRects ? TemporaryClipRects : RootRelativeClipRects, IncludeOverlayScrollbarSize); + ClipRectsContext clipRectsContext(rootLayer, hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize); + ClipRect clipRect = backgroundClipRect(clipRectsContext); // Go ahead and test the enclosing clip now. if (!clipRect.intersects(hitTestLocation)) return 0; @@ -3734,7 +3844,9 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont ClipRect bgRect; ClipRect fgRect; ClipRect outlineRect; - calculateRects(rootLayer, hitTestLocation.region(), useTemporaryClipRects ? TemporaryClipRects : RootRelativeClipRects, hitTestRect, layerBounds, bgRect, fgRect, outlineRect, IncludeOverlayScrollbarSize); + + ClipRectsContext clipRectsContext(rootLayer, hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize); + calculateRects(clipRectsContext, hitTestRect, layerBounds, bgRect, fgRect, outlineRect); // The following are used for keeping track of the z-depth of the hit point of 3d-transformed // descendants. @@ -4017,23 +4129,25 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend return 0; } -void RenderLayer::updateClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy relevancy, ShouldRespectOverflowClip respectOverflowClip) +void RenderLayer::updateClipRects(const ClipRectsContext& clipRectsContext) { + ClipRectsType clipRectsType = clipRectsContext.clipRectsType; ASSERT(clipRectsType < NumCachedClipRectsTypes); if (m_clipRectsCache && m_clipRectsCache->m_clipRects[clipRectsType]) { - ASSERT(rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]); - ASSERT(m_clipRectsCache->m_respectingOverflowClip[clipRectsType] == (respectOverflowClip == RespectOverflowClip)); + ASSERT(clipRectsContext.rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]); + ASSERT(m_clipRectsCache->m_respectingOverflowClip[clipRectsType] == (clipRectsContext.respectOverflowClip == RespectOverflowClip)); + ASSERT(m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] == clipRectsContext.overlayScrollbarSizeRelevancy); return; // We have the correct cached value. } // For transformed layers, the root layer was shifted to be us, so there is no need to // examine the parent. We want to cache clip rects with us as the root. - RenderLayer* parentLayer = rootLayer != this ? parent() : 0; + RenderLayer* parentLayer = clipRectsContext.rootLayer != this ? parent() : 0; if (parentLayer) - parentLayer->updateClipRects(rootLayer, region, clipRectsType, relevancy, respectOverflowClip); + parentLayer->updateClipRects(clipRectsContext); ClipRects clipRects; - calculateClipRects(rootLayer, region, clipRectsType, clipRects, relevancy, respectOverflowClip); + calculateClipRects(clipRectsContext, clipRects); if (!m_clipRectsCache) m_clipRectsCache = adoptPtr(new ClipRectsCache); @@ -4044,12 +4158,13 @@ void RenderLayer::updateClipRects(const RenderLayer* rootLayer, RenderRegion* re m_clipRectsCache->m_clipRects[clipRectsType] = ClipRects::create(clipRects); #ifndef NDEBUG - m_clipRectsCache->m_clipRectsRoot[clipRectsType] = rootLayer; - m_clipRectsCache->m_respectingOverflowClip[clipRectsType] = respectOverflowClip == RespectOverflowClip; + m_clipRectsCache->m_clipRectsRoot[clipRectsType] = clipRectsContext.rootLayer; + m_clipRectsCache->m_respectingOverflowClip[clipRectsType] = clipRectsContext.respectOverflowClip == RespectOverflowClip; + m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] = clipRectsContext.overlayScrollbarSizeRelevancy; #endif } -void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, ClipRects& clipRects, OverlayScrollbarSizeRelevancy relevancy, ShouldRespectOverflowClip respectOverflowClip) const +void RenderLayer::calculateClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const { if (!parent()) { // The root layer's clip rect is always infinite. @@ -4057,18 +4172,22 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* return; } + ClipRectsType clipRectsType = clipRectsContext.clipRectsType; bool useCached = clipRectsType != TemporaryClipRects; // For transformed layers, the root layer was shifted to be us, so there is no need to // examine the parent. We want to cache clip rects with us as the root. - RenderLayer* parentLayer = rootLayer != this ? parent() : 0; + RenderLayer* parentLayer = clipRectsContext.rootLayer != this ? parent() : 0; // Ensure that our parent's clip has been calculated so that we can examine the values. if (parentLayer) { if (useCached && parentLayer->clipRects(clipRectsType)) clipRects = *parentLayer->clipRects(clipRectsType); - else - parentLayer->calculateClipRects(rootLayer, region, clipRectsType, clipRects, IgnoreOverlayScrollbarSize, respectOverflowClip); + else { + ClipRectsContext parentContext(clipRectsContext); + parentContext.overlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize; // FIXME: why? + parentLayer->calculateClipRects(parentContext, clipRects); + } } else clipRects.reset(PaintInfo::infiniteRect()); @@ -4084,22 +4203,22 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* clipRects.setOverflowClipRect(clipRects.posClipRect()); // Update the clip rects that will be passed to child layers. - if ((renderer()->hasOverflowClip() && (respectOverflowClip == RespectOverflowClip || this != rootLayer)) || renderer()->hasClip()) { + if ((renderer()->hasOverflowClip() && (clipRectsContext.respectOverflowClip == RespectOverflowClip || this != clipRectsContext.rootLayer)) || renderer()->hasClip()) { // This layer establishes a clip of some kind. // This offset cannot use convertToLayerCoords, because sometimes our rootLayer may be across // some transformed layer boundary, for example, in the RenderLayerCompositor overlapMap, where // clipRects are needed in view space. LayoutPoint offset; - offset = roundedLayoutPoint(renderer()->localToContainerPoint(FloatPoint(), rootLayer->renderer())); + offset = roundedLayoutPoint(renderer()->localToContainerPoint(FloatPoint(), clipRectsContext.rootLayer->renderer())); RenderView* view = renderer()->view(); ASSERT(view); - if (view && clipRects.fixed() && rootLayer->renderer() == view) { + if (view && clipRects.fixed() && clipRectsContext.rootLayer->renderer() == view) { offset -= view->frameView()->scrollOffsetForFixedPosition(); } if (renderer()->hasOverflowClip()) { - ClipRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(offset, region, relevancy); + ClipRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(offset, clipRectsContext.region, clipRectsContext.overlayScrollbarSizeRelevancy); if (renderer()->style()->hasBorderRadius()) newOverflowClip.setHasRadius(true); clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect())); @@ -4107,7 +4226,7 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); } if (renderer()->hasClip()) { - LayoutRect newPosClip = toRenderBox(renderer())->clipRect(offset, region); + LayoutRect newPosClip = toRenderBox(renderer())->clipRect(offset, clipRectsContext.region); clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect())); clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect())); clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect())); @@ -4115,16 +4234,16 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* } } -void RenderLayer::parentClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, ClipRects& clipRects, OverlayScrollbarSizeRelevancy relevancy, ShouldRespectOverflowClip respectOverflowClip) const +void RenderLayer::parentClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const { ASSERT(parent()); - if (clipRectsType == TemporaryClipRects) { - parent()->calculateClipRects(rootLayer, region, clipRectsType, clipRects, relevancy, respectOverflowClip); + if (clipRectsContext.clipRectsType == TemporaryClipRects) { + parent()->calculateClipRects(clipRectsContext, clipRects); return; } - parent()->updateClipRects(rootLayer, region, clipRectsType, relevancy, respectOverflowClip); - clipRects = *parent()->clipRects(clipRectsType); + parent()->updateClipRects(clipRectsContext); + clipRects = *parent()->clipRects(clipRectsContext.clipRectsType); } static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRects, EPosition position) @@ -4138,27 +4257,27 @@ static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRect return parentRects.overflowClipRect(); } -ClipRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy relevancy, ShouldRespectOverflowClip respectOverflowClip) const +ClipRect RenderLayer::backgroundClipRect(const ClipRectsContext& clipRectsContext) const { ASSERT(parent()); ClipRects parentRects; - parentClipRects(rootLayer, region, clipRectsType, parentRects, relevancy, respectOverflowClip); + parentClipRects(clipRectsContext, parentRects); ClipRect backgroundClipRect = backgroundClipRectForPosition(parentRects, renderer()->style()->position()); RenderView* view = renderer()->view(); ASSERT(view); // Note: infinite clipRects should not be scrolled here, otherwise they will accidentally no longer be considered infinite. - if (parentRects.fixed() && rootLayer->renderer() == view && backgroundClipRect != PaintInfo::infiniteRect()) + if (parentRects.fixed() && clipRectsContext.rootLayer->renderer() == view && backgroundClipRect != PaintInfo::infiniteRect()) backgroundClipRect.move(view->frameView()->scrollOffsetForFixedPosition()); return backgroundClipRect; } -void RenderLayer::calculateRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, - ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, OverlayScrollbarSizeRelevancy relevancy, ShouldRespectOverflowClip respectOverflowClip) const +void RenderLayer::calculateRects(const ClipRectsContext& clipRectsContext, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, + ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, const LayoutPoint* offsetFromRoot) const { - if (rootLayer != this && parent()) { - backgroundRect = backgroundClipRect(rootLayer, region, clipRectsType, relevancy, respectOverflowClip); + if (clipRectsContext.rootLayer != this && parent()) { + backgroundRect = backgroundClipRect(clipRectsContext); backgroundRect.intersect(paintDirtyRect); } else backgroundRect = paintDirtyRect; @@ -4167,21 +4286,24 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, RenderRegion* reg outlineRect = backgroundRect; LayoutPoint offset; - convertToLayerCoords(rootLayer, offset); + if (offsetFromRoot) + offset = *offsetFromRoot; + else + convertToLayerCoords(clipRectsContext.rootLayer, offset); layerBounds = LayoutRect(offset, size()); // Update the clip rects that will be passed to child layers. if (renderer()->hasClipOrOverflowClip()) { // This layer establishes a clip of some kind. - if (renderer()->hasOverflowClip() && (this != rootLayer || respectOverflowClip == RespectOverflowClip)) { - foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(offset, region, relevancy)); + if (renderer()->hasOverflowClip() && (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip)) { + foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(offset, clipRectsContext.region, clipRectsContext.overlayScrollbarSizeRelevancy)); if (renderer()->style()->hasBorderRadius()) foregroundRect.setHasRadius(true); } if (renderer()->hasClip()) { // Clip applies to *us* as well, so go ahead and update the damageRect. - LayoutRect newPosClip = toRenderBox(renderer())->clipRect(offset, region); + LayoutRect newPosClip = toRenderBox(renderer())->clipRect(offset, clipRectsContext.region); backgroundRect.intersect(newPosClip); foregroundRect.intersect(newPosClip); outlineRect.intersect(newPosClip); @@ -4196,13 +4318,13 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, RenderRegion* reg LayoutRect layerBoundsWithVisualOverflow = renderBox()->visualOverflowRect(); renderBox()->flipForWritingMode(layerBoundsWithVisualOverflow); // Layers are in physical coordinates, so the overflow has to be flipped. layerBoundsWithVisualOverflow.moveBy(offset); - if (this != rootLayer || respectOverflowClip == RespectOverflowClip) + if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip) backgroundRect.intersect(layerBoundsWithVisualOverflow); } else { // Shift the bounds to be for our region only. - LayoutRect bounds = renderBox()->borderBoxRectInRegion(region); + LayoutRect bounds = renderBox()->borderBoxRectInRegion(clipRectsContext.region); bounds.moveBy(offset); - if (this != rootLayer || respectOverflowClip == RespectOverflowClip) + if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip) backgroundRect.intersect(bounds); } } @@ -4216,8 +4338,9 @@ LayoutRect RenderLayer::childrenClipRect() const RenderLayer* clippingRootLayer = clippingRootForPainting(); LayoutRect layerBounds; ClipRect backgroundRect, foregroundRect, outlineRect; + ClipRectsContext clipRectsContext(clippingRootLayer, 0, TemporaryClipRects); // Need to use temporary clip rects, because the value of 'dontClipToOverflow' may be different from the painting path (<rdar://problem/11844909>). - calculateRects(clippingRootLayer, 0, TemporaryClipRects, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); + calculateRects(clipRectsContext, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect.rect()), SnapOffsetForTransforms).enclosingBoundingBox(); } @@ -4229,7 +4352,8 @@ LayoutRect RenderLayer::selfClipRect() const RenderLayer* clippingRootLayer = clippingRootForPainting(); LayoutRect layerBounds; ClipRect backgroundRect, foregroundRect, outlineRect; - calculateRects(clippingRootLayer, 0, PaintingClipRects, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); + ClipRectsContext clipRectsContext(clippingRootLayer, 0, PaintingClipRects); + calculateRects(clipRectsContext, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect.rect()), SnapOffsetForTransforms).enclosingBoundingBox(); } @@ -4240,7 +4364,8 @@ LayoutRect RenderLayer::localClipRect() const RenderLayer* clippingRootLayer = clippingRootForPainting(); LayoutRect layerBounds; ClipRect backgroundRect, foregroundRect, outlineRect; - calculateRects(clippingRootLayer, 0, PaintingClipRects, PaintInfo::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); + ClipRectsContext clipRectsContext(clippingRootLayer, 0, PaintingClipRects); + calculateRects(clipRectsContext, PaintInfo::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); LayoutRect clipRect = backgroundRect.rect(); if (clipRect == PaintInfo::infiniteRect()) @@ -4275,7 +4400,7 @@ void RenderLayer::repaintBlockSelectionGaps() LayoutRect rect = m_blockSelectionGapsBounds; rect.move(-scrolledContentOffset()); - if (renderer()->hasOverflowClip()) + if (renderer()->hasOverflowClip() && !usesCompositedScrolling()) rect.intersect(toRenderBox(renderer())->overflowClipRect(LayoutPoint(), 0)); // FIXME: Regions not accounted for. if (renderer()->hasClip()) rect.intersect(toRenderBox(renderer())->clipRect(LayoutPoint(), 0)); // FIXME: Regions not accounted for. @@ -4283,7 +4408,7 @@ void RenderLayer::repaintBlockSelectionGaps() renderer()->repaintRectangle(rect); } -bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer) const +bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot) const { // Always examine the canvas and the root. // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView @@ -4304,7 +4429,7 @@ bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const Layo // Otherwise we need to compute the bounding box of this single layer and see if it intersects // the damage rect. - return boundingBox(rootLayer).intersects(damageRect); + return boundingBox(rootLayer, offsetFromRoot).intersects(damageRect); } LayoutRect RenderLayer::localBoundingBox() const @@ -4319,7 +4444,7 @@ LayoutRect RenderLayer::localBoundingBox() const // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those // floats. LayoutRect result; - if (renderer()->isRenderInline()) + if (renderer()->isInline() && renderer()->isRenderInline()) result = toRenderInline(renderer())->linesVisualOverflowBoundingBox(); else if (renderer()->isTableRow()) { // Our bounding box is just the union of all of our cells' border/overflow rects. @@ -4355,15 +4480,20 @@ LayoutRect RenderLayer::localBoundingBox() const return result; } -LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer) const +LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot) const { LayoutRect result = localBoundingBox(); if (renderer()->isBox()) renderBox()->flipForWritingMode(result); else renderer()->containingBlock()->flipForWritingMode(result); + LayoutPoint delta; - convertToLayerCoords(ancestorLayer, delta); + if (offsetFromRoot) + delta = *offsetFromRoot; + else + convertToLayerCoords(ancestorLayer, delta); + result.moveBy(delta); return result; } @@ -4373,26 +4503,34 @@ IntRect RenderLayer::absoluteBoundingBox() const return pixelSnappedIntRect(boundingBox(root())); } -IntRect RenderLayer::calculateLayerBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer, CalculateLayerBoundsFlags flags) +IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot, CalculateLayerBoundsFlags flags) const { - if (!layer->isSelfPaintingLayer()) + if (!isSelfPaintingLayer()) return IntRect(); // FIXME: This could be improved to do a check like hasVisibleNonCompositingDescendantLayers() (bug 92580). - if ((flags & ExcludeHiddenDescendants) && layer != ancestorLayer && !layer->hasVisibleContent() && !layer->hasVisibleDescendant()) + if ((flags & ExcludeHiddenDescendants) && this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant()) return IntRect(); - LayoutRect boundingBoxRect = layer->localBoundingBox(); - if (layer->renderer()->isBox()) - layer->renderBox()->flipForWritingMode(boundingBoxRect); + RenderLayerModelObject* renderer = this->renderer(); + + if (isRootLayer()) { + // The root layer is always just the size of the document. + return renderer->view()->unscaledDocumentRect(); + } + + LayoutRect boundingBoxRect = localBoundingBox(); + + if (renderer->isBox()) + toRenderBox(renderer)->flipForWritingMode(boundingBoxRect); else - layer->renderer()->containingBlock()->flipForWritingMode(boundingBoxRect); + renderer->containingBlock()->flipForWritingMode(boundingBoxRect); - if (layer->renderer()->isRoot()) { + if (renderer->isRoot()) { // If the root layer becomes composited (e.g. because some descendant with negative z-index is composited), // then it has to be big enough to cover the viewport in order to display the background. This is akin // to the code in RenderBox::paintRootBoxFillLayers(). - if (FrameView* frameView = layer->renderer()->view()->frameView()) { + if (FrameView* frameView = renderer->view()->frameView()) { LayoutUnit contentsWidth = frameView->contentsWidth(); LayoutUnit contentsHeight = frameView->contentsHeight(); @@ -4404,13 +4542,13 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* layer, const Render LayoutRect unionBounds = boundingBoxRect; if (flags & UseLocalClipRectIfPossible) { - LayoutRect localClipRect = layer->localClipRect(); + LayoutRect localClipRect = this->localClipRect(); if (localClipRect != PaintInfo::infiniteRect()) { - if ((flags & IncludeSelfTransform) && layer->paintsWithTransform(PaintBehaviorNormal)) - localClipRect = layer->transform()->mapRect(localClipRect); + if ((flags & IncludeSelfTransform) && paintsWithTransform(PaintBehaviorNormal)) + localClipRect = transform()->mapRect(localClipRect); LayoutPoint ancestorRelOffset; - layer->convertToLayerCoords(ancestorLayer, ancestorRelOffset); + convertToLayerCoords(ancestorLayer, ancestorRelOffset); localClipRect.moveBy(ancestorRelOffset); return pixelSnappedIntRect(localClipRect); } @@ -4419,49 +4557,49 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* layer, const Render // FIXME: should probably just pass 'flags' down to descendants. CalculateLayerBoundsFlags descendantFlags = DefaultCalculateLayerBoundsFlags | (flags & ExcludeHiddenDescendants); - const_cast<RenderLayer*>(layer)->updateLayerListsIfNeeded(); + const_cast<RenderLayer*>(this)->updateLayerListsIfNeeded(); - if (RenderLayer* reflection = layer->reflectionLayer()) { + if (RenderLayer* reflection = reflectionLayer()) { if (!reflection->isComposited()) { - IntRect childUnionBounds = calculateLayerBounds(reflection, layer, descendantFlags); + IntRect childUnionBounds = reflection->calculateLayerBounds(this, 0, descendantFlags); unionBounds.unite(childUnionBounds); } } - ASSERT(layer->isStackingContext() || (!layer->posZOrderList() || !layer->posZOrderList()->size())); + ASSERT(isStackingContext() || (!posZOrderList() || !posZOrderList()->size())); #if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(layer)); + LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(this)); #endif - if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + if (Vector<RenderLayer*>* negZOrderList = this->negZOrderList()) { size_t listSize = negZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = negZOrderList->at(i); if (!curLayer->isComposited()) { - IntRect childUnionBounds = calculateLayerBounds(curLayer, layer, descendantFlags); + IntRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags); unionBounds.unite(childUnionBounds); } } } - if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + if (Vector<RenderLayer*>* posZOrderList = this->posZOrderList()) { size_t listSize = posZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = posZOrderList->at(i); if (!curLayer->isComposited()) { - IntRect childUnionBounds = calculateLayerBounds(curLayer, layer, descendantFlags); + IntRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags); unionBounds.unite(childUnionBounds); } } } - if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + if (Vector<RenderLayer*>* normalFlowList = this->normalFlowList()) { size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = normalFlowList->at(i); if (!curLayer->isComposited()) { - IntRect curAbsBounds = calculateLayerBounds(curLayer, layer, descendantFlags); + IntRect curAbsBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags); unionBounds.unite(curAbsBounds); } } @@ -4471,25 +4609,28 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* layer, const Render // FIXME: We can optimize the size of the composited layers, by not enlarging // filtered areas with the outsets if we know that the filter is going to render in hardware. // https://bugs.webkit.org/show_bug.cgi?id=81239 - if ((flags & IncludeLayerFilterOutsets) && layer->renderer()->style()->hasFilterOutsets()) { + if ((flags & IncludeLayerFilterOutsets) && renderer->style()->hasFilterOutsets()) { int topOutset; int rightOutset; int bottomOutset; int leftOutset; - layer->renderer()->style()->getFilterOutsets(topOutset, rightOutset, bottomOutset, leftOutset); + renderer->style()->getFilterOutsets(topOutset, rightOutset, bottomOutset, leftOutset); unionBounds.move(-leftOutset, -topOutset); unionBounds.expand(leftOutset + rightOutset, topOutset + bottomOutset); } #endif - if ((flags & IncludeSelfTransform) && layer->paintsWithTransform(PaintBehaviorNormal)) { - TransformationMatrix* affineTrans = layer->transform(); + if ((flags & IncludeSelfTransform) && paintsWithTransform(PaintBehaviorNormal)) { + TransformationMatrix* affineTrans = transform(); boundingBoxRect = affineTrans->mapRect(boundingBoxRect); unionBounds = affineTrans->mapRect(unionBounds); } LayoutPoint ancestorRelOffset; - layer->convertToLayerCoords(ancestorLayer, ancestorRelOffset); + if (offsetFromRoot) + ancestorRelOffset = *offsetFromRoot; + else + convertToLayerCoords(ancestorLayer, ancestorRelOffset); unionBounds.moveBy(ancestorRelOffset); return pixelSnappedIntRect(unionBounds); @@ -4662,6 +4803,21 @@ void RenderLayer::rebuildZOrderLists() if (m_negZOrderList) std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex); +#if ENABLE(DIALOG_ELEMENT) + // Append layers for top layer elements after normal layer collection, to ensure they are on top regardless of z-indexes. + // The renderers of top layer elements are children of the view, sorted in top layer stacking order. + if (isRootLayer()) { + RenderObject* view = renderer()->view(); + for (RenderObject* child = view->firstChild(); child; child = child->nextSibling()) { + Element* childElement = child->node()->isElementNode() ? toElement(child->node()) : 0; + if (childElement && childElement->isInTopLayer()) { + RenderLayer* layer = toRenderLayerModelObject(child)->layer(); + m_posZOrderList->append(layer); + } + } + } +#endif + m_zOrderListsDirty = false; } @@ -4686,6 +4842,11 @@ void RenderLayer::updateNormalFlowList() void RenderLayer::collectLayers(bool includeHiddenLayers, Vector<RenderLayer*>*& posBuffer, Vector<RenderLayer*>*& negBuffer) { +#if ENABLE(DIALOG_ELEMENT) + if (isInTopLayer()) + return; +#endif + updateDescendantDependentFlags(); // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists. @@ -5201,6 +5362,9 @@ void RenderLayer::updateOrRemoveFilterEffectRenderer() RenderingMode renderingMode = renderer()->frame()->page()->settings()->acceleratedFiltersEnabled() ? Accelerated : Unaccelerated; filterRenderer->setRenderingMode(renderingMode); filterInfo->setRenderer(filterRenderer.release()); + + // We can optimize away code paths in other places if we know that there are no software filters. + renderer()->document()->view()->setHasSoftwareFilters(true); } // If the filter fails to build, remove it from the layer. It will still attempt to diff --git a/Source/WebCore/rendering/RenderLayer.h b/Source/WebCore/rendering/RenderLayer.h index 7fe448afc..19d52968c 100644 --- a/Source/WebCore/rendering/RenderLayer.h +++ b/Source/WebCore/rendering/RenderLayer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2009, 2012 Apple Inc. All rights reserved. * * Portions are Copyright (C) 1998 Netscape Communications Corporation. * @@ -62,6 +62,7 @@ class FilterOperations; class HitTestRequest; class HitTestResult; class HitTestingTransformState; +class RenderGeometryMap; class RenderMarquee; class RenderReplica; class RenderScrollbarPart; @@ -237,6 +238,7 @@ public: for (int i = 0; i < NumCachedClipRectsTypes; ++i) { m_clipRectsRoot[i] = 0; m_respectingOverflowClip[i] = false; + m_scrollbarRelevancy[i] = IgnoreOverlayScrollbarSize; } #endif } @@ -245,6 +247,7 @@ public: #ifndef NDEBUG const RenderLayer* m_clipRectsRoot[NumCachedClipRectsTypes]; bool m_respectingOverflowClip[NumCachedClipRectsTypes]; + OverlayScrollbarSizeRelevancy m_scrollbarRelevancy[NumCachedClipRectsTypes]; #endif }; @@ -388,7 +391,7 @@ public: bool canRender3DTransforms() const; void updateLayerPosition(); - + enum UpdateLayerPositionsFlag { CheckForRepaint = 1, IsCompositingUpdateRoot = 1 << 1, @@ -397,9 +400,9 @@ public: }; typedef unsigned UpdateLayerPositionsFlags; static const UpdateLayerPositionsFlags defaultFlags = CheckForRepaint | IsCompositingUpdateRoot | UpdateCompositingLayers; - // Providing |cachedOffset| prevents a outlineBoxForRepaint from walking back to the root for each layer in our subtree. - // This is an optimistic optimization that is not guaranteed to succeed. - void updateLayerPositions(LayoutPoint* offsetFromRoot, UpdateLayerPositionsFlags = defaultFlags); + + void updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags); + void updateLayerPositionsAfterScroll(); bool isPaginated() const { return m_isPaginated; } @@ -488,7 +491,7 @@ public: bool canUseConvertToLayerCoords() const { // These RenderObject have an impact on their layers' without them knowing about it. - return !renderer()->hasColumns() && !renderer()->hasTransform() && !isComposited() + return !renderer()->hasColumns() && !renderer()->hasTransform() #if ENABLE(SVG) && !renderer()->isSVGRoot() #endif @@ -525,33 +528,53 @@ public: RenderRegion* = 0, PaintLayerFlags = 0); bool hitTest(const HitTestRequest&, HitTestResult&); bool hitTest(const HitTestRequest&, const HitTestLocation&, HitTestResult&); - void paintOverlayScrollbars(GraphicsContext*, const LayoutRect& damageRect, PaintBehavior, RenderObject* paintingRoot); + void paintOverlayScrollbars(GraphicsContext*, const LayoutRect& damageRect, PaintBehavior, RenderObject* paintingRoot = 0); enum ShouldRespectOverflowClip { IgnoreOverflowClip, RespectOverflowClip }; + struct ClipRectsContext { + ClipRectsContext(const RenderLayer* inRootLayer, RenderRegion* inRegion, ClipRectsType inClipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip inRespectOverflowClip = RespectOverflowClip) + : rootLayer(inRootLayer) + , region(inRegion) + , clipRectsType(inClipRectsType) + , overlayScrollbarSizeRelevancy(inOverlayScrollbarSizeRelevancy) + , respectOverflowClip(inRespectOverflowClip) + { } + const RenderLayer* rootLayer; + RenderRegion* region; + ClipRectsType clipRectsType; + OverlayScrollbarSizeRelevancy overlayScrollbarSizeRelevancy; + ShouldRespectOverflowClip respectOverflowClip; + }; + // This method figures out our layerBounds in coordinates relative to // |rootLayer}. It also computes our background and foreground clip rects // for painting/event handling. - void calculateRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, - ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, - OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip = RespectOverflowClip) const; + // Pass offsetFromRoot if known. + void calculateRects(const ClipRectsContext&, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, + ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, const LayoutPoint* offsetFromRoot = 0) const; // Compute and cache clip rects computed with the given layer as the root - void updateClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip = RespectOverflowClip); + void updateClipRects(const ClipRectsContext&); // Compute and return the clip rects. If useCached is true, will used previously computed clip rects on ancestors // (rather than computing them all from scratch up the parent chain). - void calculateClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, ClipRects&, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip = RespectOverflowClip) const; + void calculateClipRects(const ClipRectsContext&, ClipRects&) const; - ClipRects* clipRects(ClipRectsType type) const { ASSERT(type < NumCachedClipRectsTypes); return m_clipRectsCache ? m_clipRectsCache->m_clipRects[type].get() : 0; } + ClipRects* clipRects(ClipRectsType type) const + { + ASSERT(type < NumCachedClipRectsTypes); + return m_clipRectsCache ? m_clipRectsCache->m_clipRects[type].get() : 0; + } LayoutRect childrenClipRect() const; // Returns the foreground clip rect of the layer in the document's coordinate space. LayoutRect selfClipRect() const; // Returns the background clip rect of the layer in the document's coordinate space. LayoutRect localClipRect() const; // Returns the background clip rect of the layer in the local coordinate space. - bool intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer) const; + // Pass offsetFromRoot if known. + bool intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot = 0) const; - // Bounding box relative to some ancestor layer. - LayoutRect boundingBox(const RenderLayer* rootLayer) const; + // Bounding box relative to some ancestor layer. Pass offsetFromRoot if known. + LayoutRect boundingBox(const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot = 0) const; // Bounding box in the coordinates of this layer. LayoutRect localBoundingBox() const; // Pixel snapped bounding box relative to the root. @@ -565,7 +588,8 @@ public: DefaultCalculateLayerBoundsFlags = IncludeSelfTransform | UseLocalClipRectIfPossible | IncludeLayerFilterOutsets }; typedef unsigned CalculateLayerBoundsFlags; - static IntRect calculateLayerBounds(const RenderLayer*, const RenderLayer* ancestorLayer, CalculateLayerBoundsFlags = DefaultCalculateLayerBoundsFlags); + // Can pass offsetFromRoot if known. + IntRect calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot = 0, CalculateLayerBoundsFlags = DefaultCalculateLayerBoundsFlags) const; // WARNING: This method returns the offset for the parent as this is what updateLayerPositions expects. LayoutPoint computeOffsetFromRoot(bool& hasLayerOffset) const; @@ -574,14 +598,6 @@ public: LayoutRect repaintRect() const { return m_repaintRect; } LayoutRect repaintRectIncludingNonCompositingDescendants() const; - enum UpdateLayerPositionsAfterScrollFlag { - NoFlag = 0, - HasSeenViewportConstrainedAncestor = 1 << 0, - HasSeenAncestorWithOverflowClip = 1 << 1 - }; - - typedef unsigned UpdateLayerPositionsAfterScrollFlags; - void updateLayerPositionsAfterScroll(UpdateLayerPositionsAfterScrollFlags = NoFlag); void setRepaintStatus(RepaintStatus status) { m_repaintStatus = status; } LayoutUnit staticInlinePosition() const { return m_staticInlinePosition; } @@ -686,6 +702,11 @@ public: Node* enclosingElement() const; +#if ENABLE(DIALOG_ELEMENT) + bool isInTopLayer() const; + bool isInTopLayerSubtree() const; +#endif + private: void updateZOrderLists(); void rebuildZOrderLists(); @@ -699,7 +720,7 @@ private: void setAncestorChainHasSelfPaintingLayerDescendant(); void dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); - void computeRepaintRects(LayoutPoint* offsetFromRoot = 0); + void computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* = 0); void computeRepaintRectsIncludingDescendants(); void clearRepaintRects(); @@ -715,6 +736,16 @@ private: void updateScrollbarsAfterStyleChange(const RenderStyle* oldStyle); void updateScrollbarsAfterLayout(); + void updateLayerPositions(RenderGeometryMap* = 0, UpdateLayerPositionsFlags = defaultFlags); + + enum UpdateLayerPositionsAfterScrollFlag { + NoFlag = 0, + HasSeenViewportConstrainedAncestor = 1 << 0, + HasSeenAncestorWithOverflowClip = 1 << 1 + }; + typedef unsigned UpdateLayerPositionsAfterScrollFlags; + void updateLayerPositionsAfterScroll(RenderGeometryMap*, UpdateLayerPositionsAfterScrollFlags = NoFlag); + friend IntSize RenderBox::scrolledContentOffset() const; IntSize scrolledContentOffset() const { return m_scrollOffset; } @@ -737,27 +768,31 @@ private: void updateCompositingAndLayerListsIfNeeded(); - void paintLayer(RenderLayer* rootLayer, GraphicsContext*, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, - PaintBehavior, RenderObject* paintingRoot, RenderRegion* = 0, OverlapTestRequestMap* = 0, - PaintLayerFlags = 0); - void paintLayerContentsAndReflection(RenderLayer* rootLayer, GraphicsContext*, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, - PaintBehavior, RenderObject* paintingRoot, RenderRegion* = 0, OverlapTestRequestMap* = 0, - PaintLayerFlags = 0); - void paintLayerContents(RenderLayer* rootLayer, GraphicsContext*, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, - PaintBehavior, RenderObject* paintingRoot, RenderRegion* = 0, OverlapTestRequestMap* = 0, - PaintLayerFlags = 0); - void paintList(Vector<RenderLayer*>*, RenderLayer* rootLayer, GraphicsContext* p, - const LayoutRect& paintDirtyRect, PaintBehavior, - RenderObject* paintingRoot, RenderRegion*, OverlapTestRequestMap*, - PaintLayerFlags); - void paintPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, GraphicsContext*, - const LayoutRect& paintDirtyRect, PaintBehavior, - RenderObject* paintingRoot, RenderRegion*, OverlapTestRequestMap*, - PaintLayerFlags); - void paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLayer* rootLayer, GraphicsContext*, - const LayoutRect& paintDirtyRect, PaintBehavior, - RenderObject* paintingRoot, RenderRegion*, OverlapTestRequestMap*, - PaintLayerFlags, const Vector<RenderLayer*>& columnLayers, size_t columnIndex); + struct LayerPaintingInfo { + LayerPaintingInfo(RenderLayer* inRootLayer, const LayoutRect& inDirtyRect, PaintBehavior inPaintBehavior, const LayoutSize& inSubPixelAccumulation, RenderObject* inPaintingRoot = 0, RenderRegion*inRegion = 0, OverlapTestRequestMap* inOverlapTestRequests = 0) + : rootLayer(inRootLayer) + , paintingRoot(inPaintingRoot) + , paintDirtyRect(inDirtyRect) + , subPixelAccumulation(inSubPixelAccumulation) + , region(inRegion) + , overlapTestRequests(inOverlapTestRequests) + , paintBehavior(inPaintBehavior) + { } + RenderLayer* rootLayer; + RenderObject* paintingRoot; // only paint descendants of this object + LayoutRect paintDirtyRect; // relative to rootLayer; + LayoutSize subPixelAccumulation; + RenderRegion* region; // May be null. + OverlapTestRequestMap* overlapTestRequests; // May be null. + PaintBehavior paintBehavior; + }; + + void paintLayer(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); + void paintLayerContentsAndReflection(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); + void paintLayerContents(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); + void paintList(Vector<RenderLayer*>*, GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); + void paintPaginatedChildLayer(RenderLayer* childLayer, GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); + void paintChildLayerIntoColumns(RenderLayer* childLayer, GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags, const Vector<RenderLayer*>& columnLayers, size_t columnIndex); RenderLayer* hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, const LayoutRect& hitTestRect, const HitTestLocation&, bool appliedTransform, @@ -851,8 +886,9 @@ private: void updateOrRemoveFilterEffectRenderer(); #endif - void parentClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, ClipRects&, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip = RespectOverflowClip) const; - ClipRect backgroundClipRect(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip = RespectOverflowClip) const; + void parentClipRects(const ClipRectsContext&, ClipRects&) const; + ClipRect backgroundClipRect(const ClipRectsContext&) const; + LayoutRect paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior); RenderLayer* enclosingTransformedAncestor() const; @@ -899,9 +935,14 @@ private: LayoutUnit overflowLeft() const; LayoutUnit overflowRight() const; + IntRect rectForHorizontalScrollbar(const IntRect& borderBoxRect) const; + IntRect rectForVerticalScrollbar(const IntRect& borderBoxRect) const; + LayoutUnit verticalScrollbarStart(int minX, int maxX) const; LayoutUnit horizontalScrollbarStart(int minX) const; + bool overflowControlsIntersectRect(const IntRect& localRect) const; + protected: // The bitfields are up here so they will fall into the padding from ScrollableArea on 64-bit. diff --git a/Source/WebCore/rendering/RenderLayerBacking.cpp b/Source/WebCore/rendering/RenderLayerBacking.cpp index 1f2a647f5..88be08dfe 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.cpp +++ b/Source/WebCore/rendering/RenderLayerBacking.cpp @@ -221,11 +221,22 @@ void RenderLayerBacking::updateDebugIndicators(bool showBorder, bool showRepaint m_maskLayer->setShowRepaintCounter(showRepaintCounter); } + if (m_layerForHorizontalScrollbar) + m_layerForHorizontalScrollbar->setShowDebugBorder(showBorder); + + if (m_layerForVerticalScrollbar) + m_layerForVerticalScrollbar->setShowDebugBorder(showBorder); + + if (m_layerForScrollCorner) + m_layerForScrollCorner->setShowDebugBorder(showBorder); + if (m_scrollingLayer) m_scrollingLayer->setShowDebugBorder(showBorder); - if (m_scrollingContentsLayer) + if (m_scrollingContentsLayer) { m_scrollingContentsLayer->setShowDebugBorder(showBorder); + m_scrollingContentsLayer->setShowRepaintCounter(showRepaintCounter); + } } void RenderLayerBacking::createPrimaryGraphicsLayer() @@ -370,7 +381,7 @@ void RenderLayerBacking::updateCompositedBounds() LayoutRect clippingBounds = view->unscaledDocumentRect(); if (m_owningLayer != rootLayer) - clippingBounds.intersect(m_owningLayer->backgroundClipRect(rootLayer, 0, AbsoluteClipRects).rect()); // FIXME: Incorrect for CSS regions. + clippingBounds.intersect(m_owningLayer->backgroundClipRect(RenderLayer::ClipRectsContext(rootLayer, 0, AbsoluteClipRects)).rect()); // FIXME: Incorrect for CSS regions. LayoutPoint delta; m_owningLayer->convertToLayerCoords(rootLayer, delta); @@ -609,7 +620,8 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() // Call calculateRects to get the backgroundRect which is what is used to clip the contents of this // layer. Note that we call it with temporaryClipRects = true because normally when computing clip rects // for a compositing layer, rootLayer is the layer itself. - IntRect parentClipRect = pixelSnappedIntRect(m_owningLayer->backgroundClipRect(compAncestor, 0, TemporaryClipRects, IgnoreOverlayScrollbarSize, RenderLayer::IgnoreOverflowClip).rect()); // FIXME: Incorrect for CSS regions. + RenderLayer::ClipRectsContext clipRectsContext(compAncestor, 0, TemporaryClipRects, IgnoreOverlayScrollbarSize, RenderLayer::IgnoreOverflowClip); + IntRect parentClipRect = pixelSnappedIntRect(m_owningLayer->backgroundClipRect(clipRectsContext).rect()); // FIXME: Incorrect for CSS regions. ASSERT(parentClipRect != PaintInfo::infiniteRect()); m_ancestorClippingLayer->setPosition(FloatPoint() + (parentClipRect.location() - graphicsLayerParentLocation)); m_ancestorClippingLayer->setSize(parentClipRect.size()); @@ -742,9 +754,8 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() compositor()->scrollingLayerDidChange(m_owningLayer); m_scrollingContentsLayer->setSize(scrollSize); - // FIXME: Scrolling the content layer does not need to trigger a repaint. The offset will be compensated away during painting. // FIXME: The paint offset and the scroll offset should really be separate concepts. - m_scrollingContentsLayer->setOffsetFromRenderer(scrollingContentsOffset); + m_scrollingContentsLayer->setOffsetFromRenderer(scrollingContentsOffset, GraphicsLayer::DontSetNeedsDisplay); } m_graphicsLayer->setContentsRect(contentsBox()); @@ -1303,8 +1314,14 @@ bool RenderLayerBacking::isDirectlyCompositedImage() const RenderImage* imageRenderer = toRenderImage(renderObject); if (CachedImage* cachedImage = imageRenderer->cachedImage()) { - if (cachedImage->hasImage()) - return cachedImage->imageForRenderer(imageRenderer)->isBitmapImage(); + if (!cachedImage->hasImage()) + return false; + + Image* image = cachedImage->imageForRenderer(imageRenderer); + if (!image->isBitmapImage()) + return false; + + return m_graphicsLayer->shouldDirectlyCompositeImage(image); } return false; @@ -1505,8 +1522,7 @@ void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r) void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* context, const IntRect& paintDirtyRect, // In the coords of rootLayer. - PaintBehavior paintBehavior, GraphicsLayerPaintingPhase paintingPhase, - RenderObject* paintingRoot) + PaintBehavior paintBehavior, GraphicsLayerPaintingPhase paintingPhase) { if (paintsIntoWindow() || paintsIntoCompositedAncestor()) { ASSERT_NOT_REACHED(); @@ -1526,10 +1542,11 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* paintFlags |= RenderLayer::PaintLayerPaintingOverflowContents; // FIXME: GraphicsLayers need a way to split for RenderRegions. - m_owningLayer->paintLayerContents(rootLayer, context, paintDirtyRect, LayoutSize(), paintBehavior, paintingRoot, 0, 0, paintFlags); + RenderLayer::LayerPaintingInfo paintingInfo(rootLayer, paintDirtyRect, paintBehavior, LayoutSize()); + m_owningLayer->paintLayerContents(context, paintingInfo, paintFlags); if (m_owningLayer->containsDirtyOverlayScrollbars()) - m_owningLayer->paintOverlayScrollbars(context, paintDirtyRect, paintBehavior, paintingRoot); + m_owningLayer->paintLayerContents(context, paintingInfo, paintFlags | RenderLayer::PaintLayerPaintingOverlayScrollbars); ASSERT(!m_owningLayer->m_usedTransparency); } @@ -1565,7 +1582,7 @@ void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, Graph dirtyRect.intersect(compositedBounds()); // We have to use the same root as for hit testing, because both methods can compute and cache clipRects. - paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase, renderer()); + paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase); if (m_usingTiledCacheLayer) m_owningLayer->renderer()->frame()->view()->setLastPaintTime(currentTime()); diff --git a/Source/WebCore/rendering/RenderLayerBacking.h b/Source/WebCore/rendering/RenderLayerBacking.h index 39f6ac594..cdcc030c2 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.h +++ b/Source/WebCore/rendering/RenderLayerBacking.h @@ -247,7 +247,7 @@ private: bool hasTileCacheFlatteningLayer() const { return (m_containmentLayer && m_usingTiledCacheLayer); } GraphicsLayer* tileCacheFlatteningLayer() const { return m_usingTiledCacheLayer ? m_containmentLayer.get() : 0; } - void paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect, PaintBehavior, GraphicsLayerPaintingPhase, RenderObject* paintingRoot); + void paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect, PaintBehavior, GraphicsLayerPaintingPhase); static CSSPropertyID graphicsLayerToCSSProperty(AnimatedPropertyID); static AnimatedPropertyID cssToGraphicsLayerProperty(CSSPropertyID); diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index f026d02d6..870bf1ddf 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -83,6 +83,7 @@ class RenderLayerCompositor::OverlapMap { WTF_MAKE_NONCOPYABLE(OverlapMap); public: OverlapMap() + : m_geometryMap(UseTransforms) { // Begin assuming the root layer will be composited so that there is // something on the stack. The root layer should also never get an @@ -259,11 +260,23 @@ void RenderLayerCompositor::cacheAcceleratedCompositingFlags() if (hasAcceleratedCompositing != m_hasAcceleratedCompositing || showDebugBorders != m_showDebugBorders || showRepaintCounter != m_showRepaintCounter || forceCompositingMode != m_forceCompositingMode) setCompositingLayersNeedRebuild(); + bool debugBordersChanged = m_showDebugBorders != showDebugBorders; m_hasAcceleratedCompositing = hasAcceleratedCompositing; m_showDebugBorders = showDebugBorders; m_showRepaintCounter = showRepaintCounter; m_forceCompositingMode = forceCompositingMode; m_acceleratedDrawingEnabled = acceleratedDrawingEnabled; + + if (debugBordersChanged) { + if (m_layerForHorizontalScrollbar) + m_layerForHorizontalScrollbar->setShowDebugBorder(m_showDebugBorders); + + if (m_layerForVerticalScrollbar) + m_layerForVerticalScrollbar->setShowDebugBorder(m_showDebugBorders); + + if (m_layerForScrollCorner) + m_layerForScrollCorner->setShowDebugBorder(m_showDebugBorders); + } } bool RenderLayerCompositor::canRender3DTransforms() const @@ -665,7 +678,7 @@ IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* laye { if (!canBeComposited(layer)) return IntRect(); - return RenderLayer::calculateLayerBounds(layer, ancestorLayer, RenderLayer::DefaultCalculateLayerBoundsFlags | RenderLayer::ExcludeHiddenDescendants); + return layer->calculateLayerBounds(ancestorLayer, 0, RenderLayer::DefaultCalculateLayerBoundsFlags | RenderLayer::ExcludeHiddenDescendants); } void RenderLayerCompositor::layerWasAdded(RenderLayer* /*parent*/, RenderLayer* /*child*/) @@ -710,7 +723,7 @@ void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer* boundsComputed = true; } - IntRect clipRect = pixelSnappedIntRect(layer->backgroundClipRect(rootRenderLayer(), 0, AbsoluteClipRects).rect()); // FIXME: Incorrect for CSS regions. + IntRect clipRect = pixelSnappedIntRect(layer->backgroundClipRect(RenderLayer::ClipRectsContext(rootRenderLayer(), 0, AbsoluteClipRects)).rect()); // FIXME: Incorrect for CSS regions. clipRect.scale(pageScaleFactor()); clipRect.intersect(layerBounds); overlapMap.add(layer, clipRect); @@ -1710,7 +1723,7 @@ bool RenderLayerCompositor::clippedByAncestor(RenderLayer* layer) const if (!computeClipRoot || computeClipRoot == layer) return false; - return layer->backgroundClipRect(computeClipRoot, 0, TemporaryClipRects).rect() != PaintInfo::infiniteRect(); // FIXME: Incorrect for CSS regions. + return layer->backgroundClipRect(RenderLayer::ClipRectsContext(computeClipRoot, 0, TemporaryClipRects)).rect() != PaintInfo::infiniteRect(); // FIXME: Incorrect for CSS regions. } // Return true if the given layer is a stacking context and has compositing child @@ -2213,6 +2226,7 @@ void RenderLayerCompositor::updateOverflowControlsLayers() if (requiresHorizontalScrollbarLayer()) { if (!m_layerForHorizontalScrollbar) { m_layerForHorizontalScrollbar = GraphicsLayer::create(graphicsLayerFactory(), this); + m_layerForHorizontalScrollbar->setShowDebugBorder(m_showDebugBorders); #ifndef NDEBUG m_layerForHorizontalScrollbar->setName("horizontal scrollbar"); #endif @@ -2235,6 +2249,7 @@ void RenderLayerCompositor::updateOverflowControlsLayers() if (requiresVerticalScrollbarLayer()) { if (!m_layerForVerticalScrollbar) { m_layerForVerticalScrollbar = GraphicsLayer::create(graphicsLayerFactory(), this); + m_layerForVerticalScrollbar->setShowDebugBorder(m_showDebugBorders); #ifndef NDEBUG m_layerForVerticalScrollbar->setName("vertical scrollbar"); #endif @@ -2257,6 +2272,7 @@ void RenderLayerCompositor::updateOverflowControlsLayers() if (requiresScrollCornerLayer()) { if (!m_layerForScrollCorner) { m_layerForScrollCorner = GraphicsLayer::create(graphicsLayerFactory(), this); + m_layerForScrollCorner->setShowDebugBorder(m_showDebugBorders); #ifndef NDEBUG m_layerForScrollCorner->setName("scroll corner"); #endif @@ -2590,7 +2606,9 @@ const FixedPositionViewportConstraints RenderLayerCompositor::computeFixedViewpo ASSERT(layer->isComposited()); FrameView* frameView = m_renderView->frameView(); + LayoutRect viewportRect = frameView->visibleContentRect(); + viewportRect.setLocation(toPoint(frameView->scrollOffsetForFixedPosition())); FixedPositionViewportConstraints constraints = FixedPositionViewportConstraints(); diff --git a/Source/WebCore/rendering/RenderLayerFilterInfo.cpp b/Source/WebCore/rendering/RenderLayerFilterInfo.cpp index 190de61be..6e25d573c 100644 --- a/Source/WebCore/rendering/RenderLayerFilterInfo.cpp +++ b/Source/WebCore/rendering/RenderLayerFilterInfo.cpp @@ -130,7 +130,7 @@ void RenderLayerFilterInfo::updateReferenceFilterClients(const FilterOperations& if (filterOperation->getOperationType() != FilterOperation::REFERENCE) continue; ReferenceFilterOperation* referenceFilterOperation = static_cast<ReferenceFilterOperation*>(filterOperation.get()); - CachedSVGDocumentReference* documentReference = static_cast<CachedSVGDocumentReference*>(referenceFilterOperation->data()); + CachedSVGDocumentReference* documentReference = referenceFilterOperation->cachedSVGDocumentReference(); CachedSVGDocument* cachedSVGDocument = documentReference ? documentReference->document() : 0; if (cachedSVGDocument) { diff --git a/Source/WebCore/rendering/RenderMediaControls.cpp b/Source/WebCore/rendering/RenderMediaControls.cpp index cfaed5e79..f17647b0b 100644 --- a/Source/WebCore/rendering/RenderMediaControls.cpp +++ b/Source/WebCore/rendering/RenderMediaControls.cpp @@ -197,9 +197,11 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R ASSERT_NOT_REACHED(); case MediaTextTrackDisplayContainer: case MediaTextTrackDisplay: + case MediaClosedCaptionsContainer: + case MediaClosedCaptionsTrackList: ASSERT_NOT_REACHED(); break; -} + } return false; } diff --git a/Source/WebCore/rendering/RenderMediaControlsChromium.cpp b/Source/WebCore/rendering/RenderMediaControlsChromium.cpp index 38a4e5a3e..0451fbdd2 100644 --- a/Source/WebCore/rendering/RenderMediaControlsChromium.cpp +++ b/Source/WebCore/rendering/RenderMediaControlsChromium.cpp @@ -383,6 +383,8 @@ bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType case MediaTextTrackDisplay: case MediaFullScreenVolumeSlider: case MediaFullScreenVolumeSliderThumb: + case MediaClosedCaptionsContainer: + case MediaClosedCaptionsTrackList: ASSERT_NOT_REACHED(); break; } diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp index 983aced4e..15dcdd058 100644 --- a/Source/WebCore/rendering/RenderObject.cpp +++ b/Source/WebCore/rendering/RenderObject.cpp @@ -1280,10 +1280,12 @@ RenderLayerModelObject* RenderObject::containerForRepaint() const #endif #if ENABLE(CSS_FILTERS) - if (RenderLayer* parentLayer = enclosingLayer()) { - RenderLayer* enclosingFilterLayer = parentLayer->enclosingFilterLayer(); - if (enclosingFilterLayer) - return enclosingFilterLayer->renderer(); + if (document()->view()->hasSoftwareFilters()) { + if (RenderLayer* parentLayer = enclosingLayer()) { + RenderLayer* enclosingFilterLayer = parentLayer->enclosingFilterLayer(); + if (enclosingFilterLayer) + return enclosingFilterLayer->renderer(); + } } #endif diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h index b1f541f91..118a996af 100644 --- a/Source/WebCore/rendering/RenderObject.h +++ b/Source/WebCore/rendering/RenderObject.h @@ -981,7 +981,7 @@ protected: virtual void willBeDestroyed(); void arenaDelete(RenderArena*, void* objectBase); - virtual LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* /*repaintContainer*/, LayoutPoint* /*cachedOffsetToRepaintContainer*/ = 0) const { return LayoutRect(); } + virtual LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* /*repaintContainer*/, const RenderGeometryMap* = 0) const { return LayoutRect(); } virtual bool canBeReplacedWithInlineRunIn() const; diff --git a/Source/WebCore/rendering/RenderRegion.cpp b/Source/WebCore/rendering/RenderRegion.cpp index 9ef649dd9..ce0b9d4f9 100644 --- a/Source/WebCore/rendering/RenderRegion.cpp +++ b/Source/WebCore/rendering/RenderRegion.cpp @@ -607,6 +607,7 @@ void RenderRegion::updateLogicalHeight() return; LayoutUnit newLogicalHeight = overrideLogicalContentHeight() + borderAndPaddingLogicalHeight(); + ASSERT(newLogicalHeight < LayoutUnit::max() / 2); if (newLogicalHeight > logicalHeight()) setLogicalHeight(newLogicalHeight); } diff --git a/Source/WebCore/rendering/RenderReplica.cpp b/Source/WebCore/rendering/RenderReplica.cpp index ad3acf0ba..c10bdcaf3 100644 --- a/Source/WebCore/rendering/RenderReplica.cpp +++ b/Source/WebCore/rendering/RenderReplica.cpp @@ -68,14 +68,14 @@ void RenderReplica::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) LayoutPoint adjustedPaintOffset = paintOffset + location(); - if (paintInfo.phase == PaintPhaseForeground) + if (paintInfo.phase == PaintPhaseForeground) { // Turn around and paint the parent layer. Use temporary clipRects, so that the layer doesn't end up caching clip rects // computing using the wrong rootLayer - layer()->parent()->paintLayer(layer()->transform() ? layer()->parent() : layer()->enclosingTransformedAncestor(), - paintInfo.context, paintInfo.rect, LayoutSize(), - PaintBehaviorNormal, 0, paintInfo.renderRegion, 0, - RenderLayer::PaintLayerHaveTransparency | RenderLayer::PaintLayerAppliedTransform | RenderLayer::PaintLayerTemporaryClipRects | RenderLayer::PaintLayerPaintingReflection); - else if (paintInfo.phase == PaintPhaseMask) + RenderLayer* rootPaintingLayer = layer()->transform() ? layer()->parent() : layer()->enclosingTransformedAncestor(); + RenderLayer::LayerPaintingInfo paintingInfo(rootPaintingLayer, paintInfo.rect, PaintBehaviorNormal, LayoutSize(), 0, paintInfo.renderRegion); + RenderLayer::PaintLayerFlags flags = RenderLayer::PaintLayerHaveTransparency | RenderLayer::PaintLayerAppliedTransform | RenderLayer::PaintLayerTemporaryClipRects | RenderLayer::PaintLayerPaintingReflection; + layer()->parent()->paintLayer(paintInfo.context, paintingInfo, flags); + } else if (paintInfo.phase == PaintPhaseMask) paintMask(paintInfo, adjustedPaintOffset); } diff --git a/Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp b/Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp index a7a9f4aee..272f04b93 100644 --- a/Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp +++ b/Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp @@ -37,9 +37,14 @@ namespace WebCore { +static const int autoStartPlugInSizeThresholdWidth = 1; +static const int autoStartPlugInSizeThresholdHeight = 1; +static const int startButtonPadding = 10; + RenderSnapshottedPlugIn::RenderSnapshottedPlugIn(HTMLPlugInImageElement* element) : RenderEmbeddedObject(element) , m_snapshotResource(RenderImageResource::create()) + , m_isMouseInButtonRect(false) { m_snapshotResource->initialize(this); } @@ -79,7 +84,7 @@ void RenderSnapshottedPlugIn::paintReplaced(PaintInfo& paintInfo, const LayoutPo { if (plugInImageElement()->displayState() < HTMLPlugInElement::Playing) { paintReplacedSnapshot(paintInfo, paintOffset); - theme()->paintPlugInSnapshotOverlay(this, paintInfo, paintOffset); + paintButton(paintInfo, paintOffset); return; } @@ -117,6 +122,41 @@ void RenderSnapshottedPlugIn::paintReplacedSnapshot(PaintInfo& paintInfo, const context->drawImage(image.get(), style()->colorSpace(), alignedRect, CompositeSourceOver, shouldRespectImageOrientation(), useLowQualityScaling); } +static Image* startButtonImage() +{ + static Image* buttonImage = Image::loadPlatformResource("startButton").leakRef(); + return buttonImage; +} + +static Image* startButtonPressedImage() +{ + static Image* buttonImage = Image::loadPlatformResource("startButtonPressed").leakRef(); + return buttonImage; +} + +void RenderSnapshottedPlugIn::paintButton(PaintInfo& paintInfo, const LayoutPoint& paintOffset) +{ + LayoutRect contentRect = contentBoxRect(); + if (contentRect.isEmpty()) + return; + + Image* buttonImage = startButtonImage(); + if (plugInImageElement()->active()) { + if (m_isMouseInButtonRect) + buttonImage = startButtonPressedImage(); + } else if (!plugInImageElement()->hovered()) + return; + + LayoutPoint contentLocation = paintOffset + contentRect.maxXMaxYCorner() - buttonImage->size() - LayoutSize(startButtonPadding, startButtonPadding); + paintInfo.context->drawImage(buttonImage, ColorSpaceDeviceRGB, roundedIntPoint(contentLocation), buttonImage->rect()); +} + +void RenderSnapshottedPlugIn::repaintButton() +{ + // FIXME: This is unfortunate. We should just repaint the button. + repaint(); +} + CursorDirective RenderSnapshottedPlugIn::getCursor(const LayoutPoint& point, Cursor& overrideCursor) const { if (plugInImageElement()->displayState() < HTMLPlugInElement::Playing) { @@ -132,6 +172,7 @@ void RenderSnapshottedPlugIn::handleEvent(Event* event) return; MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); + if (event->type() == eventNames().clickEvent && mouseEvent->button() == LeftButton) { plugInImageElement()->setDisplayState(HTMLPlugInElement::Playing); if (widget()) { @@ -140,7 +181,30 @@ void RenderSnapshottedPlugIn::handleEvent(Event* event) repaint(); } event->setDefaultHandled(); + } else if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent) + repaintButton(); + else if (event->type() == eventNames().mousedownEvent) { + bool isMouseInButtonRect = m_buttonRect.contains(IntPoint(mouseEvent->offsetX(), mouseEvent->offsetY())); + if (isMouseInButtonRect != m_isMouseInButtonRect) { + m_isMouseInButtonRect = isMouseInButtonRect; + repaintButton(); + } } } +void RenderSnapshottedPlugIn::layout() +{ + RenderEmbeddedObject::layout(); + if (plugInImageElement()->displayState() < HTMLPlugInElement::Playing) { + LayoutRect rect = contentBoxRect(); + int width = rect.width(); + int height = rect.height(); + if (!width || !height || (width <= autoStartPlugInSizeThresholdWidth && height <= autoStartPlugInSizeThresholdHeight)) + plugInImageElement()->setDisplayState(HTMLPlugInElement::Playing); + } + + LayoutSize buttonSize = startButtonImage()->size(); + m_buttonRect = LayoutRect(contentBoxRect().maxXMaxYCorner() - LayoutSize(startButtonPadding, startButtonPadding) - buttonSize, buttonSize); +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderSnapshottedPlugIn.h b/Source/WebCore/rendering/RenderSnapshottedPlugIn.h index 6a13a3a3f..2a1f896c7 100644 --- a/Source/WebCore/rendering/RenderSnapshottedPlugIn.h +++ b/Source/WebCore/rendering/RenderSnapshottedPlugIn.h @@ -52,9 +52,16 @@ private: virtual bool isSnapshottedPlugIn() const OVERRIDE { return true; } virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; virtual void paintReplaced(PaintInfo&, const LayoutPoint&) OVERRIDE; + void paintReplacedSnapshot(PaintInfo&, const LayoutPoint&); + void paintButton(PaintInfo&, const LayoutPoint&); + void repaintButton(); + + virtual void layout() OVERRIDE; OwnPtr<RenderImageResource> m_snapshotResource; + LayoutRect m_buttonRect; + bool m_isMouseInButtonRect; }; inline RenderSnapshottedPlugIn* toRenderSnapshottedPlugIn(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderTable.cpp b/Source/WebCore/rendering/RenderTable.cpp index 887b65c0d..7527c47a9 100644 --- a/Source/WebCore/rendering/RenderTable.cpp +++ b/Source/WebCore/rendering/RenderTable.cpp @@ -318,7 +318,7 @@ LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& st // HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not. LayoutUnit borders = 0; bool isCSSTable = !node() || !node()->hasTagName(tableTag); - if (isCSSTable && styleLogicalWidth.isFixed() && styleLogicalWidth.isPositive()) { + if (isCSSTable && styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive()) { recalcBordersInRowDirection(); if (style()->boxSizing() == CONTENT_BOX) borders = borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : paddingStart() + paddingEnd()); diff --git a/Source/WebCore/rendering/RenderTextControlMultiLine.cpp b/Source/WebCore/rendering/RenderTextControlMultiLine.cpp index 92d002829..f40994326 100644 --- a/Source/WebCore/rendering/RenderTextControlMultiLine.cpp +++ b/Source/WebCore/rendering/RenderTextControlMultiLine.cpp @@ -59,7 +59,7 @@ float RenderTextControlMultiLine::getAvgCharWidth(AtomicString family) // Since Lucida Grande is the default font, we want this to match the width // of Courier New, the default font for textareas in IE, Firefox and Safari Win. // 1229 is the avgCharWidth value in the OS/2 table for Courier New. - if (family == AtomicString("Lucida Grande")) + if (family == "Lucida Grande") return scaleEmToUnits(1229); return RenderTextControl::getAvgCharWidth(family); diff --git a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp index 967fb2acc..c7f075a4b 100644 --- a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -283,7 +283,7 @@ float RenderTextControlSingleLine::getAvgCharWidth(AtomicString family) // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and // IE for some encodings (in IE, the default font is encoding specific). // 901 is the avgCharWidth value in the OS/2 table for MS Shell Dlg. - if (family == AtomicString("Lucida Grande")) + if (family == "Lucida Grande") return scaleEmToUnits(901); return RenderTextControl::getAvgCharWidth(family); @@ -304,7 +304,7 @@ LayoutUnit RenderTextControlSingleLine::preferredContentWidth(float charWidth) c // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and // IE for some encodings (in IE, the default font is encoding specific). // 4027 is the (xMax - xMin) value in the "head" font table for MS Shell Dlg. - if (family == AtomicString("Lucida Grande")) + if (family == "Lucida Grande") maxCharWidth = scaleEmToUnits(4027); else if (hasValidAvgCharWidth(family)) maxCharWidth = roundf(style()->font().primaryFont()->maxCharWidth()); diff --git a/Source/WebCore/rendering/RenderTheme.h b/Source/WebCore/rendering/RenderTheme.h index b14749318..bbb86e192 100644 --- a/Source/WebCore/rendering/RenderTheme.h +++ b/Source/WebCore/rendering/RenderTheme.h @@ -207,6 +207,7 @@ public: virtual bool usesVerticalVolumeSlider() const { return true; } virtual double mediaControlsFadeInDuration() { return 0.1; } virtual double mediaControlsFadeOutDuration() { return 0.3; } + virtual double timeWithoutMouseMovementBeforeHidingControls() { return 3.0; } virtual String formatMediaControlsTime(float time) const; virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const; virtual String formatMediaControlsRemainingTime(float currentTime, float duration) const; @@ -242,8 +243,6 @@ public: virtual String fileListDefaultLabel(bool multipleFilesAllowed) const; virtual String fileListNameForWidth(const FileList*, const Font&, int width, bool multipleFilesAllowed) const; - virtual void paintPlugInSnapshotOverlay(RenderSnapshottedPlugIn*, const PaintInfo&, const LayoutPoint&) const { } - virtual bool shouldOpenPickerWithF4Key() const; protected: diff --git a/Source/WebCore/rendering/RenderThemeChromiumCommon.cpp b/Source/WebCore/rendering/RenderThemeChromiumCommon.cpp index 6e9079535..51f87c5e3 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumCommon.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumCommon.cpp @@ -33,7 +33,6 @@ namespace WebCore { bool RenderThemeChromiumCommon::supportsDataListUI(const AtomicString& type) { - // FIXME: We still need to support datetime, date, month, week, time, datetime-local. return type == InputTypeNames::text() || type == InputTypeNames::search() || type == InputTypeNames::url() || type == InputTypeNames::telephone() || type == InputTypeNames::email() || type == InputTypeNames::number() #if ENABLE(INPUT_TYPE_COLOR) @@ -42,6 +41,10 @@ bool RenderThemeChromiumCommon::supportsDataListUI(const AtomicString& type) #if ENABLE(CALENDAR_PICKER) || type == InputTypeNames::date() #endif + || type == InputTypeNames::datetime() + || type == InputTypeNames::datetimelocal() + || type == InputTypeNames::month() + || type == InputTypeNames::week() || type == InputTypeNames::time() || type == InputTypeNames::range(); } @@ -49,8 +52,11 @@ bool RenderThemeChromiumCommon::supportsDataListUI(const AtomicString& type) #if ENABLE(INPUT_MULTIPLE_FIELDS_UI) bool RenderThemeChromiumCommon::supportsCalendarPicker(const AtomicString& type) { - // FIXME: We'd like to support datetime, datetime-local, month, and week too. - return type == InputTypeNames::date(); + return type == InputTypeNames::date() + || type == InputTypeNames::datetime() + || type == InputTypeNames::datetimelocal() + || type == InputTypeNames::month() + || type == InputTypeNames::week(); } #endif diff --git a/Source/WebCore/rendering/RenderThemeChromiumDefault.cpp b/Source/WebCore/rendering/RenderThemeChromiumDefault.cpp new file mode 100644 index 000000000..d643729ad --- /dev/null +++ b/Source/WebCore/rendering/RenderThemeChromiumDefault.cpp @@ -0,0 +1,389 @@ +/* + * Copyright (C) 2007 Apple Inc. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2008, 2009 Google Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RenderThemeChromiumDefault.h" + +#include "CSSValueKeywords.h" +#include "Color.h" +#include "PaintInfo.h" +#include "PlatformContextSkia.h" +#include "RenderObject.h" +#include "RenderProgress.h" +#include "RenderSlider.h" +#include "ScrollbarTheme.h" +#include "UserAgentStyleSheets.h" +#include <public/Platform.h> +#include <public/WebRect.h> +#include <public/default/WebThemeEngine.h> + +namespace WebCore { + +unsigned RenderThemeChromiumDefault::m_activeSelectionBackgroundColor = + 0xff1e90ff; +unsigned RenderThemeChromiumDefault::m_activeSelectionForegroundColor = + Color::black; +unsigned RenderThemeChromiumDefault::m_inactiveSelectionBackgroundColor = + 0xffc8c8c8; +unsigned RenderThemeChromiumDefault::m_inactiveSelectionForegroundColor = + 0xff323232; + +double RenderThemeChromiumDefault::m_caretBlinkInterval; + +static const unsigned defaultButtonBackgroundColor = 0xffdddddd; + +static WebKit::WebThemeEngine::State getWebThemeState(const RenderTheme* theme, const RenderObject* o) +{ + if (!theme->isEnabled(o)) + return WebKit::WebThemeEngine::StateDisabled; + if (theme->isPressed(o)) + return WebKit::WebThemeEngine::StatePressed; + if (theme->isHovered(o)) + return WebKit::WebThemeEngine::StateHover; + + return WebKit::WebThemeEngine::StateNormal; +} + +PassRefPtr<RenderTheme> RenderThemeChromiumDefault::create() +{ + return adoptRef(new RenderThemeChromiumDefault()); +} + +// RenderTheme::themeForPage for Android is defined in RenderThemeChromiumAndroid.cpp. +#if !OS(ANDROID) +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) +{ + static RenderTheme* rt = RenderThemeChromiumDefault::create().leakRef(); + return rt; +} +#endif + +RenderThemeChromiumDefault::RenderThemeChromiumDefault() +{ + m_caretBlinkInterval = RenderTheme::caretBlinkInterval(); +} + +RenderThemeChromiumDefault::~RenderThemeChromiumDefault() +{ +} + +Color RenderThemeChromiumDefault::systemColor(int cssValueId) const +{ + static const Color defaultButtonGrayColor(0xffdddddd); + + if (cssValueId == CSSValueButtonface) + return defaultButtonGrayColor; + return RenderTheme::systemColor(cssValueId); +} + +String RenderThemeChromiumDefault::extraDefaultStyleSheet() +{ +#if !OS(WINDOWS) + return RenderThemeChromiumSkia::extraDefaultStyleSheet() + + String(themeChromiumLinuxUserAgentStyleSheet, sizeof(themeChromiumLinuxUserAgentStyleSheet)); +#else + return RenderThemeChromiumSkia::extraDefaultStyleSheet(); +#endif +} + +bool RenderThemeChromiumDefault::controlSupportsTints(const RenderObject* o) const +{ + return isEnabled(o); +} + +Color RenderThemeChromiumDefault::activeListBoxSelectionBackgroundColor() const +{ + return Color(0x28, 0x28, 0x28); +} + +Color RenderThemeChromiumDefault::activeListBoxSelectionForegroundColor() const +{ + return Color::black; +} + +Color RenderThemeChromiumDefault::inactiveListBoxSelectionBackgroundColor() const +{ + return Color(0xc8, 0xc8, 0xc8); +} + +Color RenderThemeChromiumDefault::inactiveListBoxSelectionForegroundColor() const +{ + return Color(0x32, 0x32, 0x32); +} + +Color RenderThemeChromiumDefault::platformActiveSelectionBackgroundColor() const +{ + return m_activeSelectionBackgroundColor; +} + +Color RenderThemeChromiumDefault::platformInactiveSelectionBackgroundColor() const +{ + return m_inactiveSelectionBackgroundColor; +} + +Color RenderThemeChromiumDefault::platformActiveSelectionForegroundColor() const +{ + return m_activeSelectionForegroundColor; +} + +Color RenderThemeChromiumDefault::platformInactiveSelectionForegroundColor() const +{ + return m_inactiveSelectionForegroundColor; +} + +#if ENABLE(DATALIST_ELEMENT) +IntSize RenderThemeChromiumDefault::sliderTickSize() const +{ + return IntSize(1, 6); +} + +int RenderThemeChromiumDefault::sliderTickOffsetFromTrackCenter() const +{ + return -16; +} +#endif + +void RenderThemeChromiumDefault::adjustSliderThumbSize(RenderStyle* style, Element* element) const +{ + IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartSliderThumb); + + if (style->appearance() == SliderThumbHorizontalPart) { + style->setWidth(Length(size.width(), Fixed)); + style->setHeight(Length(size.height(), Fixed)); + } else if (style->appearance() == SliderThumbVerticalPart) { + style->setWidth(Length(size.height(), Fixed)); + style->setHeight(Length(size.width(), Fixed)); + } else + RenderThemeChromiumSkia::adjustSliderThumbSize(style, element); +} + +bool RenderThemeChromiumDefault::supportsControlTints() const +{ + return true; +} + +void RenderThemeChromiumDefault::setCaretBlinkInterval(double interval) +{ + m_caretBlinkInterval = interval; +} + +double RenderThemeChromiumDefault::caretBlinkIntervalInternal() const +{ + return m_caretBlinkInterval; +} + +void RenderThemeChromiumDefault::setSelectionColors( + unsigned activeBackgroundColor, + unsigned activeForegroundColor, + unsigned inactiveBackgroundColor, + unsigned inactiveForegroundColor) +{ + m_activeSelectionBackgroundColor = activeBackgroundColor; + m_activeSelectionForegroundColor = activeForegroundColor; + m_inactiveSelectionBackgroundColor = inactiveBackgroundColor; + m_inactiveSelectionForegroundColor = inactiveForegroundColor; +} + +bool RenderThemeChromiumDefault::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& rect) +{ + WebKit::WebThemeEngine::ExtraParams extraParams; + WebKit::WebCanvas* canvas = i.context->platformContext()->canvas(); + extraParams.button.checked = isChecked(o); + extraParams.button.indeterminate = isIndeterminate(o); + + WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartCheckbox, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams); + return false; +} + +void RenderThemeChromiumDefault::setCheckboxSize(RenderStyle* style) const +{ + // If the width and height are both specified, then we have nothing to do. + if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) + return; + + IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartCheckbox); + setSizeIfAuto(style, size); +} + +bool RenderThemeChromiumDefault::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& rect) +{ + WebKit::WebThemeEngine::ExtraParams extraParams; + WebKit::WebCanvas* canvas = i.context->platformContext()->canvas(); + extraParams.button.checked = isChecked(o); + + WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartRadio, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams); + return false; +} + +void RenderThemeChromiumDefault::setRadioSize(RenderStyle* style) const +{ + // If the width and height are both specified, then we have nothing to do. + if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) + return; + + IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartRadio); + setSizeIfAuto(style, size); +} + +bool RenderThemeChromiumDefault::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& rect) +{ + WebKit::WebThemeEngine::ExtraParams extraParams; + WebKit::WebCanvas* canvas = i.context->platformContext()->canvas(); + extraParams.button.isDefault = isDefault(o); + extraParams.button.hasBorder = true; + extraParams.button.backgroundColor = defaultButtonBackgroundColor; + if (o->hasBackground()) + extraParams.button.backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor).rgb(); + + WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartButton, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams); + return false; +} + +bool RenderThemeChromiumDefault::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& rect) +{ + // WebThemeEngine does not handle border rounded corner and background image + // so return true to draw CSS border and background. + if (o->style()->hasBorderRadius() || o->style()->hasBackgroundImage()) + return true; + + ControlPart part = o->style()->appearance(); + + WebKit::WebThemeEngine::ExtraParams extraParams; + extraParams.textField.isTextArea = part == TextAreaPart; + extraParams.textField.isListbox = part == ListboxPart; + + WebKit::WebCanvas* canvas = i.context->platformContext()->canvas(); + + // Fallback to white if the specified color object is invalid. + Color backgroundColor(Color::white); + if (o->style()->visitedDependentColor(CSSPropertyBackgroundColor).isValid()) + backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor); + extraParams.textField.backgroundColor = backgroundColor.rgb(); + + WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartTextField, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams); + return false; +} + +bool RenderThemeChromiumDefault::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& rect) +{ + if (!o->isBox()) + return false; + + const int right = rect.x() + rect.width(); + const int middle = rect.y() + rect.height() / 2; + + WebKit::WebThemeEngine::ExtraParams extraParams; + extraParams.menuList.arrowX = (o->style()->direction() == RTL) ? rect.x() + 7 : right - 13; + extraParams.menuList.arrowY = middle; + const RenderBox* box = toRenderBox(o); + // Match Chromium Win behaviour of showing all borders if any are shown. + extraParams.menuList.hasBorder = box->borderRight() || box->borderLeft() || box->borderTop() || box->borderBottom(); + extraParams.menuList.hasBorderRadius = o->style()->hasBorderRadius(); + // Fallback to transparent if the specified color object is invalid. + extraParams.menuList.backgroundColor = Color::transparent; + if (o->hasBackground()) + extraParams.menuList.backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor).rgb(); + + WebKit::WebCanvas* canvas = i.context->platformContext()->canvas(); + + WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartMenuList, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams); + return false; +} + +bool RenderThemeChromiumDefault::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& rect) +{ + WebKit::WebThemeEngine::ExtraParams extraParams; + WebKit::WebCanvas* canvas = i.context->platformContext()->canvas(); + extraParams.slider.vertical = o->style()->appearance() == SliderVerticalPart; + + WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartSliderTrack, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams); + +#if ENABLE(DATALIST_ELEMENT) + paintSliderTicks(o, i, rect); +#endif + + return false; +} + +bool RenderThemeChromiumDefault::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& rect) +{ + WebKit::WebThemeEngine::ExtraParams extraParams; + WebKit::WebCanvas* canvas = i.context->platformContext()->canvas(); + extraParams.slider.vertical = o->style()->appearance() == SliderThumbVerticalPart; + extraParams.slider.inDrag = isPressed(o); + + WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartSliderThumb, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams); + return false; +} + +void RenderThemeChromiumDefault::adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle* style, Element*) const +{ + IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartInnerSpinButton); + + style->setWidth(Length(size.width(), Fixed)); + style->setMinWidth(Length(size.width(), Fixed)); +} + +bool RenderThemeChromiumDefault::paintInnerSpinButton(RenderObject* o, const PaintInfo& i, const IntRect& rect) +{ + WebKit::WebThemeEngine::ExtraParams extraParams; + WebKit::WebCanvas* canvas = i.context->platformContext()->canvas(); + extraParams.innerSpin.spinUp = (controlStatesForRenderer(o) & SpinUpState); + extraParams.innerSpin.readOnly = isReadOnlyControl(o); + + WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartInnerSpinButton, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams); + return false; +} + +#if ENABLE(PROGRESS_ELEMENT) + +bool RenderThemeChromiumDefault::paintProgressBar(RenderObject* o, const PaintInfo& i, const IntRect& rect) +{ + if (!o->isProgress()) + return true; + + RenderProgress* renderProgress = toRenderProgress(o); + IntRect valueRect = progressValueRectFor(renderProgress, rect); + + WebKit::WebThemeEngine::ExtraParams extraParams; + extraParams.progressBar.determinate = renderProgress->isDeterminate(); + extraParams.progressBar.valueRectX = valueRect.x(); + extraParams.progressBar.valueRectY = valueRect.y(); + extraParams.progressBar.valueRectWidth = valueRect.width(); + extraParams.progressBar.valueRectHeight = valueRect.height(); + + DirectionFlippingScope scope(o, i, rect); + WebKit::WebCanvas* canvas = i.context->platformContext()->canvas(); + WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartProgressBar, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams); + return false; +} + +#endif + +bool RenderThemeChromiumDefault::shouldOpenPickerWithF4Key() const +{ + return true; +} + +} // namespace WebCore diff --git a/Source/WebCore/rendering/RenderThemeChromiumDefault.h b/Source/WebCore/rendering/RenderThemeChromiumDefault.h new file mode 100644 index 000000000..129b482cb --- /dev/null +++ b/Source/WebCore/rendering/RenderThemeChromiumDefault.h @@ -0,0 +1,109 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008, 2009 Google, Inc. + * All rights reserved. + * Copyright (C) 2009 Kenneth Rohde Christiansen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef RenderThemeChromiumDefault_h +#define RenderThemeChromiumDefault_h + +#include "RenderThemeChromiumSkia.h" + +namespace WebCore { + +class RenderThemeChromiumDefault : public RenderThemeChromiumSkia { +public: + static PassRefPtr<RenderTheme> create(); + virtual String extraDefaultStyleSheet(); + + virtual Color systemColor(int cssValidId) const; + + // A method asking if the control changes its tint when the window has focus or not. + virtual bool controlSupportsTints(const RenderObject*) const; + + // List Box selection color + virtual Color activeListBoxSelectionBackgroundColor() const; + virtual Color activeListBoxSelectionForegroundColor() const; + virtual Color inactiveListBoxSelectionBackgroundColor() const; + virtual Color inactiveListBoxSelectionForegroundColor() const; + + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveSelectionForegroundColor() const; + virtual Color platformInactiveSelectionForegroundColor() const; + +#if ENABLE(DATALIST_ELEMENT) + virtual IntSize sliderTickSize() const OVERRIDE; + virtual int sliderTickOffsetFromTrackCenter() const OVERRIDE; +#endif + virtual void adjustSliderThumbSize(RenderStyle*, Element*) const; + + static void setCaretBlinkInterval(double); + virtual double caretBlinkIntervalInternal() const; + + virtual bool paintCheckbox(RenderObject*, const PaintInfo&, const IntRect&); + virtual void setCheckboxSize(RenderStyle*) const; + + virtual bool paintRadio(RenderObject*, const PaintInfo&, const IntRect&); + virtual void setRadioSize(RenderStyle*) const; + + virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); + + virtual void adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&); + + virtual bool popsMenuBySpaceOrReturn() const OVERRIDE { return true; } + +#if ENABLE(PROGRESS_ELEMENT) + virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&); +#endif + + virtual bool shouldOpenPickerWithF4Key() const OVERRIDE; + + static void setSelectionColors(unsigned activeBackgroundColor, unsigned activeForegroundColor, unsigned inactiveBackgroundColor, unsigned inactiveForegroundColor); + +protected: + RenderThemeChromiumDefault(); + virtual ~RenderThemeChromiumDefault(); + +private: + // A general method asking if any control tinting is supported at all. + virtual bool supportsControlTints() const; + + static double m_caretBlinkInterval; + + static unsigned m_activeSelectionBackgroundColor; + static unsigned m_activeSelectionForegroundColor; + static unsigned m_inactiveSelectionBackgroundColor; + static unsigned m_inactiveSelectionForegroundColor; +}; + +} // namespace WebCore + +#endif // RenderThemeChromiumDefault_h diff --git a/Source/WebCore/rendering/RenderThemeChromiumFontProvider.cpp b/Source/WebCore/rendering/RenderThemeChromiumFontProvider.cpp new file mode 100644 index 000000000..78068e537 --- /dev/null +++ b/Source/WebCore/rendering/RenderThemeChromiumFontProvider.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderThemeChromiumFontProvider.h" + +#include <wtf/StdLibExtras.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +// The default variable-width font size. We use this as the default font +// size for the "system font", and as a base size (which we then shrink) for +// form control fonts. +// static +float RenderThemeChromiumFontProvider::s_defaultFontSize = 16.0; + +// We aim to match IE here. +// -IE uses a font based on the encoding as the default font for form controls. +// -Gecko uses MS Shell Dlg (actually calls GetStockObject(DEFAULT_GUI_FONT), +// which returns MS Shell Dlg) +// -Safari uses Lucida Grande. +// +// FIXME: The only case where we know we don't match IE is for ANSI encodings. +// IE uses MS Shell Dlg there, which we render incorrectly at certain pixel +// sizes (e.g. 15px). So, for now we just use Arial. +const String& RenderThemeChromiumFontProvider::defaultGUIFont() +{ + DEFINE_STATIC_LOCAL(String, fontFace, (ASCIILiteral("Arial"))); + return fontFace; +} + +} // namespace WebCore diff --git a/Source/WebCore/rendering/RenderThemeChromiumFontProvider.h b/Source/WebCore/rendering/RenderThemeChromiumFontProvider.h new file mode 100644 index 000000000..0f7eeac27 --- /dev/null +++ b/Source/WebCore/rendering/RenderThemeChromiumFontProvider.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderThemeChromiumFontProvider_h +#define RenderThemeChromiumFontProvider_h + +namespace WTF { +class String; +} + +namespace WebCore { + +class FontDescription; + +class RenderThemeChromiumFontProvider { +public: + static void systemFont(int propId, FontDescription&); + static void setDefaultFontSize(int); + +protected: + static const WTF::String& defaultGUIFont(); + + static float s_defaultFontSize; +}; + +} // namespace WebCore + +#endif // RenderThemeChromiumFontProvider_h diff --git a/Source/WebCore/rendering/RenderThemeChromiumFontProviderLinux.cpp b/Source/WebCore/rendering/RenderThemeChromiumFontProviderLinux.cpp new file mode 100644 index 000000000..009c72417 --- /dev/null +++ b/Source/WebCore/rendering/RenderThemeChromiumFontProviderLinux.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderThemeChromiumFontProvider.h" + +#include "CSSValueKeywords.h" +#include "FontDescription.h" + +#include <wtf/StdLibExtras.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +// static +void RenderThemeChromiumFontProvider::setDefaultFontSize(int fontSize) +{ + s_defaultFontSize = static_cast<float>(fontSize); +} + +// static +void RenderThemeChromiumFontProvider::systemFont(int propId, FontDescription& fontDescription) +{ + float fontSize = s_defaultFontSize; + + switch (propId) { + case CSSValueWebkitMiniControl: + case CSSValueWebkitSmallControl: + case CSSValueWebkitControl: + // Why 2 points smaller? Because that's what Gecko does. Note that we + // are assuming a 96dpi screen, which is the default that we use on + // Windows. + static const float pointsPerInch = 72.0f; + static const float pixelsPerInch = 96.0f; + fontSize -= (2.0f / pointsPerInch) * pixelsPerInch; + break; + } + + fontDescription.firstFamily().setFamily(defaultGUIFont()); + fontDescription.setSpecifiedSize(fontSize); + fontDescription.setIsAbsoluteSize(true); + fontDescription.setGenericFamily(FontDescription::NoFamily); + fontDescription.setWeight(FontWeightNormal); + fontDescription.setItalic(false); +} + +} // namespace WebCore diff --git a/Source/WebCore/rendering/RenderThemeChromiumFontProviderWin.cpp b/Source/WebCore/rendering/RenderThemeChromiumFontProviderWin.cpp new file mode 100644 index 000000000..faf3c942b --- /dev/null +++ b/Source/WebCore/rendering/RenderThemeChromiumFontProviderWin.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderThemeChromiumFontProvider.h" + +#include "CSSValueKeywords.h" +#include "FontDescription.h" +#include "HWndDC.h" +#include "SystemInfo.h" + +#include <windows.h> +#include <wtf/text/WTFString.h> + +#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \ + offsetof(structName, member) + \ + (sizeof static_cast<structName*>(0)->member) +#define NONCLIENTMETRICS_SIZE_PRE_VISTA \ + SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) + +namespace WebCore { + +static FontDescription& smallSystemFont() +{ + DEFINE_STATIC_LOCAL(FontDescription, font, ()); + return font; +} + +static FontDescription& menuFont() +{ + DEFINE_STATIC_LOCAL(FontDescription, font, ()); + return font; +} + +static FontDescription& labelFont() +{ + DEFINE_STATIC_LOCAL(FontDescription, font, ()); + return font; +} + +// Converts |points| to pixels. One point is 1/72 of an inch. +static float pointsToPixels(float points) +{ + static float pixelsPerInch = 0.0f; + if (!pixelsPerInch) { + HWndDC hdc(0); // What about printing? Is this the right DC? + if (hdc) // Can this ever actually be 0? + pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY); + else + pixelsPerInch = 96.0f; + } + + static const float pointsPerInch = 72.0f; + return points / pointsPerInch * pixelsPerInch; +} + +static void getNonClientMetrics(NONCLIENTMETRICS* metrics) +{ + static UINT size = (windowsVersion() >= WindowsVista) ? + sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; + metrics->cbSize = size; + bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0); + ASSERT(success); +} + +// Return the height of system font |font| in pixels. We use this size by +// default for some non-form-control elements. +static float systemFontSize(const LOGFONT& font) +{ + float size = -font.lfHeight; + if (size < 0) { + HFONT hFont = CreateFontIndirect(&font); + if (hFont) { + HWndDC hdc(0); // What about printing? Is this the right DC? + if (hdc) { + HGDIOBJ hObject = SelectObject(hdc, hFont); + TEXTMETRIC tm; + GetTextMetrics(hdc, &tm); + SelectObject(hdc, hObject); + size = tm.tmAscent; + } + DeleteObject(hFont); + } + } + + // The "codepage 936" bit here is from Gecko; apparently this helps make + // fonts more legible in Simplified Chinese where the default font size is + // too small. + // + // FIXME: http://b/1119883 Since this is only used for "small caption", + // "menu", and "status bar" objects, I'm not sure how much this even + // matters. Plus the Gecko patch went in back in 2002, and maybe this + // isn't even relevant anymore. We should investigate whether this should + // be removed, or perhaps broadened to be "any CJK locale". + // + return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size; +} + +// static +void RenderThemeChromiumFontProvider::systemFont(int propId, FontDescription& fontDescription) +{ + // This logic owes much to RenderThemeSafari.cpp. + FontDescription* cachedDesc = 0; + AtomicString faceName; + float fontSize = 0; + switch (propId) { + case CSSValueSmallCaption: + cachedDesc = &smallSystemFont(); + if (!smallSystemFont().isAbsoluteSize()) { + NONCLIENTMETRICS metrics; + getNonClientMetrics(&metrics); + faceName = AtomicString(metrics.lfSmCaptionFont.lfFaceName, wcslen(metrics.lfSmCaptionFont.lfFaceName)); + fontSize = systemFontSize(metrics.lfSmCaptionFont); + } + break; + case CSSValueMenu: + cachedDesc = &menuFont(); + if (!menuFont().isAbsoluteSize()) { + NONCLIENTMETRICS metrics; + getNonClientMetrics(&metrics); + faceName = AtomicString(metrics.lfMenuFont.lfFaceName, wcslen(metrics.lfMenuFont.lfFaceName)); + fontSize = systemFontSize(metrics.lfMenuFont); + } + break; + case CSSValueStatusBar: + cachedDesc = &labelFont(); + if (!labelFont().isAbsoluteSize()) { + NONCLIENTMETRICS metrics; + getNonClientMetrics(&metrics); + faceName = metrics.lfStatusFont.lfFaceName; + fontSize = systemFontSize(metrics.lfStatusFont); + } + break; + case CSSValueWebkitMiniControl: + case CSSValueWebkitSmallControl: + case CSSValueWebkitControl: + faceName = defaultGUIFont(); + // Why 2 points smaller? Because that's what Gecko does. + fontSize = s_defaultFontSize - pointsToPixels(2); + break; + default: + faceName = defaultGUIFont(); + fontSize = s_defaultFontSize; + break; + } + + if (!cachedDesc) + cachedDesc = &fontDescription; + + if (fontSize) { + cachedDesc->firstFamily().setFamily(faceName); + cachedDesc->setIsAbsoluteSize(true); + cachedDesc->setGenericFamily(FontDescription::NoFamily); + cachedDesc->setSpecifiedSize(fontSize); + cachedDesc->setWeight(FontWeightNormal); + cachedDesc->setItalic(false); + } + fontDescription = *cachedDesc; +} + +// static +void RenderThemeChromiumFontProvider::setDefaultFontSize(int fontSize) +{ + s_defaultFontSize = static_cast<float>(fontSize); + + // Reset cached fonts. + smallSystemFont() = menuFont() = labelFont() = FontDescription(); +} + +} // namespace WebCore diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.h b/Source/WebCore/rendering/RenderThemeChromiumMac.h index 1f5a81484..5acd13af5 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumMac.h +++ b/Source/WebCore/rendering/RenderThemeChromiumMac.h @@ -25,11 +25,11 @@ #define RenderThemeChromiumMac_h #import "RenderThemeChromiumCommon.h" -#import "RenderThemeMac.h" +#import "RenderThemeMacShared.h" namespace WebCore { -class RenderThemeChromiumMac : public RenderThemeMac { +class RenderThemeChromiumMac : public RenderThemeMacShared { public: static PassRefPtr<RenderTheme> create(); diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.mm b/Source/WebCore/rendering/RenderThemeChromiumMac.mm index 56d9ea607..91fe6ba66 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumMac.mm +++ b/Source/WebCore/rendering/RenderThemeChromiumMac.mm @@ -99,7 +99,7 @@ int RenderThemeChromiumMac::popupInternalPaddingLeft(RenderStyle* style) const if (style->appearance() == TextFieldPart) return autofillPopupHorizontalPadding; - return RenderThemeMac::popupInternalPaddingLeft(style); + return RenderThemeMacShared::popupInternalPaddingLeft(style); } int RenderThemeChromiumMac::popupInternalPaddingRight(RenderStyle* style) const @@ -107,7 +107,7 @@ int RenderThemeChromiumMac::popupInternalPaddingRight(RenderStyle* style) const if (style->appearance() == TextFieldPart) return autofillPopupHorizontalPadding; - return RenderThemeMac::popupInternalPaddingRight(style); + return RenderThemeMacShared::popupInternalPaddingRight(style); } // Updates the control tint (a.k.a. active state) of |cell| (from |o|). @@ -171,7 +171,7 @@ String RenderThemeChromiumMac::extraFullScreenStyleSheet() String RenderThemeChromiumMac::extraDefaultStyleSheet() { - return RenderThemeMac::extraDefaultStyleSheet() + + return RenderThemeMacShared::extraDefaultStyleSheet() + String(themeChromiumUserAgentStyleSheet, sizeof(themeChromiumUserAgentStyleSheet)); } diff --git a/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp b/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp index 4e504cab4..968423d81 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp @@ -39,6 +39,7 @@ #include "RenderObject.h" #include "RenderProgress.h" #include "RenderSlider.h" +#include "RenderThemeChromiumFontProvider.h" #include "ScrollbarTheme.h" #include "TimeRanges.h" #include "TransformationMatrix.h" @@ -70,23 +71,6 @@ static const float minSearchFieldResultsDecorationSize = 9; static const float maxSearchFieldResultsDecorationSize = 30; static const float defaultSearchFieldResultsButtonWidth = 18; -// We aim to match IE here. -// -IE uses a font based on the encoding as the default font for form controls. -// -Gecko uses MS Shell Dlg (actually calls GetStockObject(DEFAULT_GUI_FONT), -// which returns MS Shell Dlg) -// -Safari uses Lucida Grande. -// -// FIXME: The only case where we know we don't match IE is for ANSI encodings. -// IE uses MS Shell Dlg there, which we render incorrectly at certain pixel -// sizes (e.g. 15px). So, for now we just use Arial. -const String& RenderThemeChromiumSkia::defaultGUIFont() -{ - DEFINE_STATIC_LOCAL(String, fontFace, (ASCIILiteral("Arial"))); - return fontFace; -} - -float RenderThemeChromiumSkia::defaultFontSize = 16.0; - RenderThemeChromiumSkia::RenderThemeChromiumSkia() { } @@ -183,27 +167,7 @@ double RenderThemeChromiumSkia::caretBlinkInterval() const void RenderThemeChromiumSkia::systemFont(int propId, FontDescription& fontDescription) const { - float fontSize = defaultFontSize; - - switch (propId) { - case CSSValueWebkitMiniControl: - case CSSValueWebkitSmallControl: - case CSSValueWebkitControl: - // Why 2 points smaller? Because that's what Gecko does. Note that we - // are assuming a 96dpi screen, which is the default that we use on - // Windows. - static const float pointsPerInch = 72.0f; - static const float pixelsPerInch = 96.0f; - fontSize -= (2.0f / pointsPerInch) * pixelsPerInch; - break; - } - - fontDescription.firstFamily().setFamily(defaultGUIFont()); - fontDescription.setSpecifiedSize(fontSize); - fontDescription.setIsAbsoluteSize(true); - fontDescription.setGenericFamily(FontDescription::NoFamily); - fontDescription.setWeight(FontWeightNormal); - fontDescription.setItalic(false); + RenderThemeChromiumFontProvider::systemFont(propId, fontDescription); } int RenderThemeChromiumSkia::minimumMenuListSize(RenderStyle* style) const @@ -573,7 +537,7 @@ int RenderThemeChromiumSkia::popupInternalPaddingBottom(RenderStyle* style) cons // static void RenderThemeChromiumSkia::setDefaultFontSize(int fontSize) { - defaultFontSize = static_cast<float>(fontSize); + RenderThemeChromiumFontProvider::setDefaultFontSize(fontSize); } double RenderThemeChromiumSkia::caretBlinkIntervalInternal() const diff --git a/Source/WebCore/rendering/RenderThemeChromiumSkia.h b/Source/WebCore/rendering/RenderThemeChromiumSkia.h index 87b4e81dd..8dc3a3a36 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumSkia.h +++ b/Source/WebCore/rendering/RenderThemeChromiumSkia.h @@ -36,142 +36,142 @@ namespace WebCore { class RenderProgress; class RenderThemeChromiumSkia : public RenderTheme { - public: - RenderThemeChromiumSkia(); - virtual ~RenderThemeChromiumSkia(); +public: + RenderThemeChromiumSkia(); + virtual ~RenderThemeChromiumSkia(); - virtual String extraDefaultStyleSheet(); - virtual String extraQuirksStyleSheet(); + virtual String extraDefaultStyleSheet(); + virtual String extraQuirksStyleSheet(); #if ENABLE(VIDEO) - virtual String extraMediaControlsStyleSheet(); + virtual String extraMediaControlsStyleSheet(); +#endif + +#if ENABLE(TOUCH_EVENTS) + virtual Color platformTapHighlightColor() const OVERRIDE + { + return Color(defaultTapHighlightColor); + } #endif - // A method asking if the theme's controls actually care about redrawing when hovered. - virtual bool supportsHover(const RenderStyle*) const; + // A method asking if the theme's controls actually care about redrawing when hovered. + virtual bool supportsHover(const RenderStyle*) const; - // A method asking if the theme is able to draw the focus ring. - virtual bool supportsFocusRing(const RenderStyle*) const; + // A method asking if the theme is able to draw the focus ring. + virtual bool supportsFocusRing(const RenderStyle*) const; - virtual bool supportsDataListUI(const AtomicString& type) const OVERRIDE; + virtual bool supportsDataListUI(const AtomicString& type) const OVERRIDE; #if ENABLE(VIDEO_TRACK) - virtual bool supportsClosedCaptioning() const OVERRIDE; + virtual bool supportsClosedCaptioning() const OVERRIDE; #endif - // The platform selection color. - virtual Color platformActiveSelectionBackgroundColor() const; - virtual Color platformInactiveSelectionBackgroundColor() const; - virtual Color platformActiveSelectionForegroundColor() const; - virtual Color platformInactiveSelectionForegroundColor() const; - virtual Color platformFocusRingColor() const; + // The platform selection color. + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveSelectionForegroundColor() const; + virtual Color platformInactiveSelectionForegroundColor() const; + virtual Color platformFocusRingColor() const; - // To change the blink interval, override caretBlinkIntervalInternal instead of this one so that we may share layout test code an intercepts. - virtual double caretBlinkInterval() const; + // To change the blink interval, override caretBlinkIntervalInternal instead of this one so that we may share layout test code an intercepts. + virtual double caretBlinkInterval() const; - // System fonts. - virtual void systemFont(int propId, FontDescription&) const; + // System fonts. + virtual void systemFont(int propId, FontDescription&) const; - virtual int minimumMenuListSize(RenderStyle*) const; + virtual int minimumMenuListSize(RenderStyle*) const; - virtual void setCheckboxSize(RenderStyle*) const; + virtual void setCheckboxSize(RenderStyle*) const; - virtual void setRadioSize(RenderStyle*) const; + virtual void setRadioSize(RenderStyle*) const; - virtual void adjustButtonStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual void adjustButtonStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSliderThumbSize(RenderStyle*, Element*) const; - virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual String formatMediaControlsTime(float time) const; - virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const; - virtual String formatMediaControlsRemainingTime(float currentTime, float duration) const; - virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintMediaSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSliderThumbSize(RenderStyle*, Element*) const; + virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual String formatMediaControlsTime(float time) const; + virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const; + virtual String formatMediaControlsRemainingTime(float currentTime, float duration) const; + virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&); - // MenuList refers to an unstyled menulist (meaning a menulist without - // background-color or border set) and MenuListButton refers to a styled - // menulist (a menulist with background-color or border set). They have - // this distinction to support showing aqua style themes whenever they - // possibly can, which is something we don't want to replicate. - // - // In short, we either go down the MenuList code path or the MenuListButton - // codepath. We never go down both. And in both cases, they render the - // entire menulist. - virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&); + // MenuList refers to an unstyled menulist (meaning a menulist without + // background-color or border set) and MenuListButton refers to a styled + // menulist (a menulist with background-color or border set). They have + // this distinction to support showing aqua style themes whenever they + // possibly can, which is something we don't want to replicate. + // + // In short, we either go down the MenuList code path or the MenuListButton + // codepath. We never go down both. And in both cases, they render the + // entire menulist. + virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&); #if ENABLE(PROGRESS_ELEMENT) - virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const; - virtual double animationDurationForProgressBar(RenderProgress*) const; + virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const; + virtual double animationDurationForProgressBar(RenderProgress*) const; #endif - // These methods define the padding for the MenuList's inner block. - virtual int popupInternalPaddingLeft(RenderStyle*) const; - virtual int popupInternalPaddingRight(RenderStyle*) const; - virtual int popupInternalPaddingTop(RenderStyle*) const; - virtual int popupInternalPaddingBottom(RenderStyle*) const; + // These methods define the padding for the MenuList's inner block. + virtual int popupInternalPaddingLeft(RenderStyle*) const; + virtual int popupInternalPaddingRight(RenderStyle*) const; + virtual int popupInternalPaddingTop(RenderStyle*) const; + virtual int popupInternalPaddingBottom(RenderStyle*) const; #if ENABLE(VIDEO) - // Media controls - virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return true; } - virtual bool usesVerticalVolumeSlider() const { return false; } + // Media controls + virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return true; } + virtual bool usesVerticalVolumeSlider() const { return false; } #endif - // Provide a way to pass the default font size from the Settings object - // to the render theme. FIXME: http://b/1129186 A cleaner way would be - // to remove the default font size from this object and have callers - // that need the value to get it directly from the appropriate Settings - // object. - static void setDefaultFontSize(int); + // Provide a way to pass the default font size from the Settings object + // to the render theme. FIXME: http://b/1129186 A cleaner way would be + // to remove the default font size from this object and have callers + // that need the value to get it directly from the appropriate Settings + // object. + static void setDefaultFontSize(int); - protected: - static const String& defaultGUIFont(); +protected: + virtual double caretBlinkIntervalInternal() const; - // The default variable-width font size. We use this as the default font - // size for the "system font", and as a base size (which we then shrink) for - // form control fonts. - static float defaultFontSize; + virtual int menuListArrowPadding() const; - virtual double caretBlinkIntervalInternal() const; + static void setSizeIfAuto(RenderStyle*, const IntSize&); - virtual int menuListArrowPadding() const; +#if ENABLE(PROGRESS_ELEMENT) + IntRect determinateProgressValueRectFor(RenderProgress*, const IntRect&) const; + IntRect indeterminateProgressValueRectFor(RenderProgress*, const IntRect&) const; + IntRect progressValueRectFor(RenderProgress*, const IntRect&) const; - static void setSizeIfAuto(RenderStyle*, const IntSize&); + class DirectionFlippingScope { + public: + DirectionFlippingScope(RenderObject*, const PaintInfo&, const IntRect&); + ~DirectionFlippingScope(); -#if ENABLE(PROGRESS_ELEMENT) - IntRect determinateProgressValueRectFor(RenderProgress*, const IntRect&) const; - IntRect indeterminateProgressValueRectFor(RenderProgress*, const IntRect&) const; - IntRect progressValueRectFor(RenderProgress*, const IntRect&) const; - - class DirectionFlippingScope { - public: - DirectionFlippingScope(RenderObject*, const PaintInfo&, const IntRect&); - ~DirectionFlippingScope(); - - private: - bool m_needsFlipping; - const PaintInfo& m_paintInfo; - }; + private: + bool m_needsFlipping; + const PaintInfo& m_paintInfo; + }; #endif private: @@ -188,6 +188,8 @@ private: int menuListInternalPadding(RenderStyle*, int paddingType) const; bool paintMediaButtonInternal(GraphicsContext*, const IntRect&, Image*); IntRect convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, LayoutRect partRect, const IntRect& localOffset) const; + + static const RGBA32 defaultTapHighlightColor = 0x2e000000; // 18% black. }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderThemeChromiumWin.cpp b/Source/WebCore/rendering/RenderThemeChromiumWin.cpp index 04e893f81..709904c59 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumWin.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumWin.cpp @@ -35,7 +35,6 @@ #include "GraphicsContext.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" -#include "HWndDC.h" #include "LayoutTestSupport.h" #include "MediaControlElements.h" #include "PaintInfo.h" @@ -43,6 +42,7 @@ #include "RenderBox.h" #include "RenderProgress.h" #include "RenderSlider.h" +#include "RenderThemeChromiumCommon.h" #include "ScrollbarTheme.h" #include "SystemInfo.h" #include "TransparencyWin.h" @@ -52,12 +52,6 @@ // FIXME: This dependency should eventually be removed. #include <skia/ext/skia_utils_win.h> -#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \ - offsetof(structName, member) + \ - (sizeof static_cast<structName*>(0)->member) -#define NONCLIENTMETRICS_SIZE_PRE_VISTA \ - SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) - namespace WebCore { // The standard width for the menu list drop-down button when run under @@ -135,19 +129,6 @@ bool ThemePainter::s_hasInstance = false; } // namespace -static void getNonClientMetrics(NONCLIENTMETRICS* metrics) -{ - static UINT size = (windowsVersion() >= WindowsVista) ? - sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; - metrics->cbSize = size; - bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0); - ASSERT(success); -} - -static FontDescription smallSystemFont; -static FontDescription menuFont; -static FontDescription labelFont; - // Internal static helper functions. We don't put them in an anonymous // namespace so they have easier access to the WebCore namespace. @@ -166,55 +147,6 @@ static bool supportsFocus(ControlPart appearance) return false; } -// Return the height of system font |font| in pixels. We use this size by -// default for some non-form-control elements. -static float systemFontSize(const LOGFONT& font) -{ - float size = -font.lfHeight; - if (size < 0) { - HFONT hFont = CreateFontIndirect(&font); - if (hFont) { - HWndDC hdc(0); // What about printing? Is this the right DC? - if (hdc) { - HGDIOBJ hObject = SelectObject(hdc, hFont); - TEXTMETRIC tm; - GetTextMetrics(hdc, &tm); - SelectObject(hdc, hObject); - size = tm.tmAscent; - } - DeleteObject(hFont); - } - } - - // The "codepage 936" bit here is from Gecko; apparently this helps make - // fonts more legible in Simplified Chinese where the default font size is - // too small. - // - // FIXME: http://b/1119883 Since this is only used for "small caption", - // "menu", and "status bar" objects, I'm not sure how much this even - // matters. Plus the Gecko patch went in back in 2002, and maybe this - // isn't even relevant anymore. We should investigate whether this should - // be removed, or perhaps broadened to be "any CJK locale". - // - return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size; -} - -// Converts |points| to pixels. One point is 1/72 of an inch. -static float pointsToPixels(float points) -{ - static float pixelsPerInch = 0.0f; - if (!pixelsPerInch) { - HWndDC hdc(0); // What about printing? Is this the right DC? - if (hdc) // Can this ever actually be NULL? - pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY); - else - pixelsPerInch = 96.0f; - } - - static const float pointsPerInch = 72.0f; - return points / pointsPerInch * pixelsPerInch; -} - static double querySystemBlinkInterval(double defaultInterval) { UINT blinkTime = GetCaretBlinkTime(); @@ -285,67 +217,6 @@ Color RenderThemeChromiumWin::platformInactiveTextSearchHighlightColor() const return Color(0xff, 0xff, 0x96); // Yellow. } -void RenderThemeChromiumWin::systemFont(int propId, FontDescription& fontDescription) const -{ - // This logic owes much to RenderThemeSafari.cpp. - FontDescription* cachedDesc = 0; - AtomicString faceName; - float fontSize = 0; - switch (propId) { - case CSSValueSmallCaption: - cachedDesc = &smallSystemFont; - if (!smallSystemFont.isAbsoluteSize()) { - NONCLIENTMETRICS metrics; - getNonClientMetrics(&metrics); - faceName = AtomicString(metrics.lfSmCaptionFont.lfFaceName, wcslen(metrics.lfSmCaptionFont.lfFaceName)); - fontSize = systemFontSize(metrics.lfSmCaptionFont); - } - break; - case CSSValueMenu: - cachedDesc = &menuFont; - if (!menuFont.isAbsoluteSize()) { - NONCLIENTMETRICS metrics; - getNonClientMetrics(&metrics); - faceName = AtomicString(metrics.lfMenuFont.lfFaceName, wcslen(metrics.lfMenuFont.lfFaceName)); - fontSize = systemFontSize(metrics.lfMenuFont); - } - break; - case CSSValueStatusBar: - cachedDesc = &labelFont; - if (!labelFont.isAbsoluteSize()) { - NONCLIENTMETRICS metrics; - getNonClientMetrics(&metrics); - faceName = metrics.lfStatusFont.lfFaceName; - fontSize = systemFontSize(metrics.lfStatusFont); - } - break; - case CSSValueWebkitMiniControl: - case CSSValueWebkitSmallControl: - case CSSValueWebkitControl: - faceName = defaultGUIFont(); - // Why 2 points smaller? Because that's what Gecko does. - fontSize = defaultFontSize - pointsToPixels(2); - break; - default: - faceName = defaultGUIFont(); - fontSize = defaultFontSize; - break; - } - - if (!cachedDesc) - cachedDesc = &fontDescription; - - if (fontSize) { - cachedDesc->firstFamily().setFamily(faceName); - cachedDesc->setIsAbsoluteSize(true); - cachedDesc->setGenericFamily(FontDescription::NoFamily); - cachedDesc->setSpecifiedSize(fontSize); - cachedDesc->setWeight(FontWeightNormal); - cachedDesc->setItalic(false); - } - fontDescription = *cachedDesc; -} - // Map a CSSValue* system color to an index understood by GetSysColor(). static int cssValueIdToSysColorIndex(int cssValueId) { @@ -536,15 +407,6 @@ bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const PaintInfo& i, return false; } -// static -void RenderThemeChromiumWin::setDefaultFontSize(int fontSize) -{ - RenderThemeChromiumSkia::setDefaultFontSize(fontSize); - - // Reset cached fonts. - smallSystemFont = menuFont = labelFont = FontDescription(); -} - double RenderThemeChromiumWin::caretBlinkIntervalInternal() const { // This involves a system call, so we cache the result. diff --git a/Source/WebCore/rendering/RenderThemeChromiumWin.h b/Source/WebCore/rendering/RenderThemeChromiumWin.h index 85cca45ff..bf335c7b8 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumWin.h +++ b/Source/WebCore/rendering/RenderThemeChromiumWin.h @@ -57,8 +57,6 @@ namespace WebCore { virtual Color platformActiveTextSearchHighlightColor() const; virtual Color platformInactiveTextSearchHighlightColor() const; - // System fonts. - virtual void systemFont(int propId, FontDescription&) const; virtual Color systemColor(int cssValueId) const; #if ENABLE(DATALIST_ELEMENT) @@ -86,10 +84,6 @@ namespace WebCore { // entire menulist. virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&); - // Override RenderThemeChromiumSkia's setDefaultFontSize method to also reset the local font property caches. - // See comment in RenderThemeChromiumSkia::setDefaultFontSize() regarding ugliness of this hack. - static void setDefaultFontSize(int); - virtual void adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&); diff --git a/Source/WebCore/rendering/RenderThemeMac.h b/Source/WebCore/rendering/RenderThemeMac.h index 3288471ad..03d809ed6 100644 --- a/Source/WebCore/rendering/RenderThemeMac.h +++ b/Source/WebCore/rendering/RenderThemeMac.h @@ -23,131 +23,24 @@ #ifndef RenderThemeMac_h #define RenderThemeMac_h -#import "RenderTheme.h" -#import <wtf/HashMap.h> +#import "RenderThemeMacShared.h" #import <wtf/RetainPtr.h> - -OBJC_CLASS WebCoreRenderThemeNotificationObserver; - namespace WebCore { class RenderProgress; class RenderStyle; -class RenderThemeMac : public RenderTheme { +class RenderThemeMac : public RenderThemeMacShared { public: static PassRefPtr<RenderTheme> create(); - // A method asking if the control changes its tint when the window has focus or not. - virtual bool controlSupportsTints(const RenderObject*) const; - - // A general method asking if any control tinting is supported at all. - virtual bool supportsControlTints() const { return true; } - - virtual void adjustRepaintRect(const RenderObject*, IntRect&) OVERRIDE; - - virtual bool isControlStyled(const RenderStyle*, const BorderData&, - const FillLayer&, const Color& backgroundColor) const; - - virtual Color platformActiveSelectionBackgroundColor() const; - virtual Color platformInactiveSelectionBackgroundColor() const; - virtual Color platformActiveListBoxSelectionBackgroundColor() const; - virtual Color platformActiveListBoxSelectionForegroundColor() const; - virtual Color platformInactiveListBoxSelectionBackgroundColor() const; - virtual Color platformInactiveListBoxSelectionForegroundColor() const; - virtual Color platformFocusRingColor() const; - - virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return SmallScrollbar; } - - virtual void platformColorsDidChange(); - - // System fonts. - virtual void systemFont(int cssValueId, FontDescription&) const; - - virtual int minimumMenuListSize(RenderStyle*) const; - - virtual void adjustSliderThumbSize(RenderStyle*, Element*) const; - -#if ENABLE(DATALIST_ELEMENT) - virtual IntSize sliderTickSize() const OVERRIDE; - virtual int sliderTickOffsetFromTrackCenter() const OVERRIDE; -#endif - - virtual int popupInternalPaddingLeft(RenderStyle*) const; - virtual int popupInternalPaddingRight(RenderStyle*) const; - virtual int popupInternalPaddingTop(RenderStyle*) const; - virtual int popupInternalPaddingBottom(RenderStyle*) const; - - virtual bool paintCapsLockIndicator(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - - virtual bool popsMenuByArrowKeys() const OVERRIDE { return true; } - -#if ENABLE(METER_ELEMENT) - virtual IntSize meterSizeForBounds(const RenderMeter*, const IntRect&) const OVERRIDE; - virtual bool paintMeter(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool supportsMeter(ControlPart) const; -#endif - -#if ENABLE(PROGRESS_ELEMENT) - // Returns the repeat interval of the animation for the progress bar. - virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const; - // Returns the duration of the animation for the progress bar. - virtual double animationDurationForProgressBar(RenderProgress*) const; -#endif - - virtual Color systemColor(int cssValueId) const; - // Controls color values returned from platformFocusRingColor(). systemColor() will be used when false. - virtual bool usesTestModeFocusRingColor() const; - // A view associated to the contained document. Subclasses may not have such a view and return a fake. virtual NSView* documentViewFor(RenderObject*) const; - virtual void paintPlugInSnapshotOverlay(RenderSnapshottedPlugIn*, const PaintInfo&, const LayoutPoint&) const OVERRIDE; - protected: RenderThemeMac(); virtual ~RenderThemeMac(); - virtual bool supportsSelectionForegroundColors() const { return false; } - - virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const; - - virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const; - - virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const; - - virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const; - -#if ENABLE(PROGRESS_ELEMENT) - virtual void adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&); -#endif - - virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSliderTrackStyle(StyleResolver*, RenderStyle*, Element*) const; - - virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSliderThumbStyle(StyleResolver*, RenderStyle*, Element*) const; - - virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const; - - virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&); - - virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&); - - virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&); - - virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&); - #if ENABLE(VIDEO) virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&); @@ -174,87 +67,12 @@ protected: virtual String extraFullScreenStyleSheet(); #endif - virtual bool supportsClosedCaptioning() const { return true; } virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const; virtual bool usesMediaControlStatusDisplay(); virtual bool usesMediaControlVolumeSlider() const; virtual void adjustMediaSliderThumbSize(RenderStyle*) const; virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const OVERRIDE; #endif - - virtual bool shouldShowPlaceholderWhenFocused() const; - -private: - virtual String fileListNameForWidth(const FileList*, const Font&, int width, bool multipleFilesAllowed) const OVERRIDE; - - IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const; - - FloatRect convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const; - - // Get the control size based off the font. Used by some of the controls (like buttons). - NSControlSize controlSizeForFont(RenderStyle*) const; - NSControlSize controlSizeForSystemFont(RenderStyle*) const; - void setControlSize(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel = 1.0f); - void setSizeFromFont(RenderStyle*, const IntSize* sizes) const; - IntSize sizeForFont(RenderStyle*, const IntSize* sizes) const; - IntSize sizeForSystemFont(RenderStyle*, const IntSize* sizes) const; - void setFontFromControlSize(StyleResolver*, RenderStyle*, NSControlSize) const; - - void updateCheckedState(NSCell*, const RenderObject*); - void updateEnabledState(NSCell*, const RenderObject*); - void updateFocusedState(NSCell*, const RenderObject*); - void updatePressedState(NSCell*, const RenderObject*); - // An optional hook for subclasses to update the control tint of NSCell. - virtual void updateActiveState(NSCell*, const RenderObject*) {} - - // Helpers for adjusting appearance and for painting - - void setPopupButtonCellState(const RenderObject*, const IntRect&); - const IntSize* popupButtonSizes() const; - const int* popupButtonMargins() const; - const int* popupButtonPadding(NSControlSize) const; - void paintMenuListButtonGradients(RenderObject*, const PaintInfo&, const IntRect&); - const IntSize* menuListSizes() const; - - const IntSize* searchFieldSizes() const; - const IntSize* cancelButtonSizes() const; - const IntSize* resultsButtonSizes() const; - void setSearchCellState(RenderObject*, const IntRect&); - void setSearchFieldSize(RenderStyle*) const; - - NSPopUpButtonCell* popupButton() const; - NSSearchFieldCell* search() const; - NSMenu* searchMenuTemplate() const; - NSSliderCell* sliderThumbHorizontal() const; - NSSliderCell* sliderThumbVertical() const; - NSTextFieldCell* textField() const; - -#if ENABLE(METER_ELEMENT) - NSLevelIndicatorStyle levelIndicatorStyleFor(ControlPart) const; - NSLevelIndicatorCell* levelIndicatorFor(const RenderMeter*) const; -#endif - -#if ENABLE(PROGRESS_ELEMENT) - int minimumProgressBarHeight(RenderStyle*) const; - const IntSize* progressBarSizes() const; - const int* progressBarMargins(NSControlSize) const; -#endif - -private: - mutable RetainPtr<NSPopUpButtonCell> m_popupButton; - mutable RetainPtr<NSSearchFieldCell> m_search; - mutable RetainPtr<NSMenu> m_searchMenuTemplate; - mutable RetainPtr<NSSliderCell> m_sliderThumbHorizontal; - mutable RetainPtr<NSSliderCell> m_sliderThumbVertical; - mutable RetainPtr<NSLevelIndicatorCell> m_levelIndicator; - mutable RetainPtr<NSTextFieldCell> m_textField; - - bool m_isSliderThumbHorizontalPressed; - bool m_isSliderThumbVerticalPressed; - - mutable HashMap<int, RGBA32> m_systemColorCache; - - RetainPtr<WebCoreRenderThemeNotificationObserver> m_notificationObserver; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderThemeMac.mm b/Source/WebCore/rendering/RenderThemeMac.mm index e0837fdc5..fadd09011 100644 --- a/Source/WebCore/rendering/RenderThemeMac.mm +++ b/Source/WebCore/rendering/RenderThemeMac.mm @@ -20,137 +20,32 @@ #import "config.h" #import "RenderThemeMac.h" -#import "BitmapImage.h" -#import "ColorMac.h" -#import "CSSValueList.h" -#import "CSSValueKeywords.h" -#import "Document.h" #import "Element.h" -#import "FileList.h" -#import "FrameView.h" #import "GraphicsContextCG.h" -#import "HTMLInputElement.h" #import "HTMLMediaElement.h" -#import "HTMLNames.h" -#import "Image.h" -#import "ImageBuffer.h" #import "LocalCurrentGraphicsContext.h" -#import "LocalizedStrings.h" #import "MediaControlElements.h" #import "PaintInfo.h" #import "RenderMedia.h" #import "RenderMediaControls.h" -#import "RenderSlider.h" -#import "RenderSnapshottedPlugIn.h" #import "RenderView.h" -#import "SharedBuffer.h" -#import "StringTruncator.h" -#import "StyleResolver.h" #import "TimeRanges.h" #import "ThemeMac.h" -#import "WebCoreNSCellExtras.h" #import "WebCoreSystemInterface.h" #import "UserAgentStyleSheets.h" #import <Carbon/Carbon.h> #import <Cocoa/Cocoa.h> #import <wtf/RetainPtr.h> -#import <wtf/StdLibExtras.h> -#import <math.h> - -#import "RenderProgress.h" - -#if ENABLE(METER_ELEMENT) -#include "RenderMeter.h" -#include "HTMLMeterElement.h" -#endif - - -using namespace std; - -// The methods in this file are specific to the Mac OS X platform. - -// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari. - -// We estimate the animation rate of a Mac OS X progress bar is 33 fps. -// Hard code the value here because we haven't found API for it. -const double progressAnimationFrameRate = 0.033; - -// Mac OS X progress bar animation seems to have 256 frames. -const double progressAnimationNumFrames = 256; - -@interface WebCoreRenderThemeNotificationObserver : NSObject -{ - WebCore::RenderTheme *_theme; -} - -- (id)initWithTheme:(WebCore::RenderTheme *)theme; -- (void)systemColorsDidChange:(NSNotification *)notification; - -@end - -@implementation WebCoreRenderThemeNotificationObserver - -- (id)initWithTheme:(WebCore::RenderTheme *)theme -{ - if (!(self = [super init])) - return nil; - - _theme = theme; - return self; -} - -- (void)systemColorsDidChange:(NSNotification *)unusedNotification -{ - ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]); - _theme->platformColorsDidChange(); -} - -@end - -@interface NSTextFieldCell (WKDetails) -- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus; -@end - - -@interface WebCoreTextFieldCell : NSTextFieldCell -- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus; -@end - -@implementation WebCoreTextFieldCell -- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus -{ - // FIXME: This is a post-Lion-only workaround for <rdar://problem/11385461>. When that bug is resolved, we should remove this code. - CFMutableDictionaryRef coreUIDrawOptions = CFDictionaryCreateMutableCopy(NULL, 0, [super _coreUIDrawOptionsWithFrame:cellFrame inView:controlView includeFocus:includeFocus]); - CFDictionarySetValue(coreUIDrawOptions, @"borders only", kCFBooleanTrue); - return (CFDictionaryRef)[NSMakeCollectable(coreUIDrawOptions) autorelease]; -} -@end namespace WebCore { using namespace HTMLNames; -enum { - topMargin, - rightMargin, - bottomMargin, - leftMargin -}; - -enum { - topPadding, - rightPadding, - bottomPadding, - leftPadding -}; - -#if PLATFORM(MAC) PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*) { static RenderTheme* rt = RenderThemeMac::create().leakRef(); return rt; } -#endif PassRefPtr<RenderTheme> RenderThemeMac::create() { @@ -158,1575 +53,20 @@ PassRefPtr<RenderTheme> RenderThemeMac::create() } RenderThemeMac::RenderThemeMac() - : m_isSliderThumbHorizontalPressed(false) - , m_isSliderThumbVerticalPressed(false) - , m_notificationObserver(AdoptNS, [[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this]) { - [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get() - selector:@selector(systemColorsDidChange:) - name:NSSystemColorsDidChangeNotification - object:nil]; } RenderThemeMac::~RenderThemeMac() { - [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()]; -} - -Color RenderThemeMac::platformActiveSelectionBackgroundColor() const -{ - NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; - return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); -} - -Color RenderThemeMac::platformInactiveSelectionBackgroundColor() const -{ - NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; - return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); -} - -Color RenderThemeMac::platformActiveListBoxSelectionBackgroundColor() const -{ - NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; - return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); -} - -Color RenderThemeMac::platformActiveListBoxSelectionForegroundColor() const -{ - return Color::white; -} - -Color RenderThemeMac::platformInactiveListBoxSelectionForegroundColor() const -{ - return Color::black; -} - -Color RenderThemeMac::platformFocusRingColor() const -{ - if (usesTestModeFocusRingColor()) - return oldAquaFocusRingColor(); - - return systemColor(CSSValueWebkitFocusRingColor); -} - -Color RenderThemeMac::platformInactiveListBoxSelectionBackgroundColor() const -{ - return platformInactiveSelectionBackgroundColor(); -} - -static FontWeight toFontWeight(NSInteger appKitFontWeight) -{ - ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15); - if (appKitFontWeight > 14) - appKitFontWeight = 14; - else if (appKitFontWeight < 1) - appKitFontWeight = 1; - - static FontWeight fontWeights[] = { - FontWeight100, - FontWeight100, - FontWeight200, - FontWeight300, - FontWeight400, - FontWeight500, - FontWeight600, - FontWeight600, - FontWeight700, - FontWeight800, - FontWeight800, - FontWeight900, - FontWeight900, - FontWeight900 - }; - return fontWeights[appKitFontWeight - 1]; -} - -void RenderThemeMac::systemFont(int cssValueId, FontDescription& fontDescription) const -{ - DEFINE_STATIC_LOCAL(FontDescription, systemFont, ()); - DEFINE_STATIC_LOCAL(FontDescription, smallSystemFont, ()); - DEFINE_STATIC_LOCAL(FontDescription, menuFont, ()); - DEFINE_STATIC_LOCAL(FontDescription, labelFont, ()); - DEFINE_STATIC_LOCAL(FontDescription, miniControlFont, ()); - DEFINE_STATIC_LOCAL(FontDescription, smallControlFont, ()); - DEFINE_STATIC_LOCAL(FontDescription, controlFont, ()); - - FontDescription* cachedDesc; - NSFont* font = nil; - switch (cssValueId) { - case CSSValueSmallCaption: - cachedDesc = &smallSystemFont; - if (!smallSystemFont.isAbsoluteSize()) - font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]; - break; - case CSSValueMenu: - cachedDesc = &menuFont; - if (!menuFont.isAbsoluteSize()) - font = [NSFont menuFontOfSize:[NSFont systemFontSize]]; - break; - case CSSValueStatusBar: - cachedDesc = &labelFont; - if (!labelFont.isAbsoluteSize()) - font = [NSFont labelFontOfSize:[NSFont labelFontSize]]; - break; - case CSSValueWebkitMiniControl: - cachedDesc = &miniControlFont; - if (!miniControlFont.isAbsoluteSize()) - font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]]; - break; - case CSSValueWebkitSmallControl: - cachedDesc = &smallControlFont; - if (!smallControlFont.isAbsoluteSize()) - font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]; - break; - case CSSValueWebkitControl: - cachedDesc = &controlFont; - if (!controlFont.isAbsoluteSize()) - font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; - break; - default: - cachedDesc = &systemFont; - if (!systemFont.isAbsoluteSize()) - font = [NSFont systemFontOfSize:[NSFont systemFontSize]]; - } - - if (font) { - NSFontManager *fontManager = [NSFontManager sharedFontManager]; - cachedDesc->setIsAbsoluteSize(true); - cachedDesc->setGenericFamily(FontDescription::NoFamily); - cachedDesc->firstFamily().setFamily([font familyName]); - cachedDesc->setSpecifiedSize([font pointSize]); - cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font])); - cachedDesc->setItalic([fontManager traitsOfFont:font] & NSItalicFontMask); - } - fontDescription = *cachedDesc; -} - -static RGBA32 convertNSColorToColor(NSColor *color) -{ - NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; - if (colorInColorSpace) { - static const double scaleFactor = nextafter(256.0, 0.0); - return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]), - static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]), - static_cast<int>(scaleFactor * [colorInColorSpace blueComponent])); - } - - // This conversion above can fail if the NSColor in question is an NSPatternColor - // (as many system colors are). These colors are actually a repeating pattern - // not just a solid color. To work around this we simply draw a 1x1 image of - // the color and use that pixel's color. It might be better to use an average of - // the colors in the pattern instead. - NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil - pixelsWide:1 - pixelsHigh:1 - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:4 - bitsPerPixel:32]; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]]; - NSEraseRect(NSMakeRect(0, 0, 1, 1)); - [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)]; - [NSGraphicsContext restoreGraphicsState]; - - NSUInteger pixel[4]; - [offscreenRep getPixel:pixel atX:0 y:0]; - - [offscreenRep release]; - - return makeRGB(pixel[0], pixel[1], pixel[2]); -} - -static RGBA32 menuBackgroundColor() -{ - NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil - pixelsWide:1 - pixelsHigh:1 - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:4 - bitsPerPixel:32]; - - CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]); - CGRect rect = CGRectMake(0, 0, 1, 1); - HIThemeMenuDrawInfo drawInfo; - drawInfo.version = 0; - drawInfo.menuType = kThemeMenuTypePopUp; - HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted); - - NSUInteger pixel[4]; - [offscreenRep getPixel:pixel atX:0 y:0]; - - [offscreenRep release]; - - return makeRGB(pixel[0], pixel[1], pixel[2]); -} - -void RenderThemeMac::platformColorsDidChange() -{ - m_systemColorCache.clear(); - RenderTheme::platformColorsDidChange(); -} - -Color RenderThemeMac::systemColor(int cssValueId) const -{ - { - HashMap<int, RGBA32>::iterator it = m_systemColorCache.find(cssValueId); - if (it != m_systemColorCache.end()) - return it->value; - } - - Color color; - switch (cssValueId) { - case CSSValueActiveborder: - color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); - break; - case CSSValueActivecaption: - color = convertNSColorToColor([NSColor windowFrameTextColor]); - break; - case CSSValueAppworkspace: - color = convertNSColorToColor([NSColor headerColor]); - break; - case CSSValueBackground: - // Use theme independent default - break; - case CSSValueButtonface: - // We use this value instead of NSColor's controlColor to avoid website incompatibilities. - // We may want to change this to use the NSColor in future. - color = 0xFFC0C0C0; - break; - case CSSValueButtonhighlight: - color = convertNSColorToColor([NSColor controlHighlightColor]); - break; - case CSSValueButtonshadow: - color = convertNSColorToColor([NSColor controlShadowColor]); - break; - case CSSValueButtontext: - color = convertNSColorToColor([NSColor controlTextColor]); - break; - case CSSValueCaptiontext: - color = convertNSColorToColor([NSColor textColor]); - break; - case CSSValueGraytext: - color = convertNSColorToColor([NSColor disabledControlTextColor]); - break; - case CSSValueHighlight: - color = convertNSColorToColor([NSColor selectedTextBackgroundColor]); - break; - case CSSValueHighlighttext: - color = convertNSColorToColor([NSColor selectedTextColor]); - break; - case CSSValueInactiveborder: - color = convertNSColorToColor([NSColor controlBackgroundColor]); - break; - case CSSValueInactivecaption: - color = convertNSColorToColor([NSColor controlBackgroundColor]); - break; - case CSSValueInactivecaptiontext: - color = convertNSColorToColor([NSColor textColor]); - break; - case CSSValueInfobackground: - // There is no corresponding NSColor for this so we use a hard coded value. - color = 0xFFFBFCC5; - break; - case CSSValueInfotext: - color = convertNSColorToColor([NSColor textColor]); - break; - case CSSValueMenu: - color = menuBackgroundColor(); - break; - case CSSValueMenutext: - color = convertNSColorToColor([NSColor selectedMenuItemTextColor]); - break; - case CSSValueScrollbar: - color = convertNSColorToColor([NSColor scrollBarColor]); - break; - case CSSValueText: - color = convertNSColorToColor([NSColor textColor]); - break; - case CSSValueThreeddarkshadow: - color = convertNSColorToColor([NSColor controlDarkShadowColor]); - break; - case CSSValueThreedshadow: - color = convertNSColorToColor([NSColor shadowColor]); - break; - case CSSValueThreedface: - // We use this value instead of NSColor's controlColor to avoid website incompatibilities. - // We may want to change this to use the NSColor in future. - color = 0xFFC0C0C0; - break; - case CSSValueThreedhighlight: - color = convertNSColorToColor([NSColor highlightColor]); - break; - case CSSValueThreedlightshadow: - color = convertNSColorToColor([NSColor controlLightHighlightColor]); - break; - case CSSValueWebkitFocusRingColor: - color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); - break; - case CSSValueWindow: - color = convertNSColorToColor([NSColor windowBackgroundColor]); - break; - case CSSValueWindowframe: - color = convertNSColorToColor([NSColor windowFrameColor]); - break; - case CSSValueWindowtext: - color = convertNSColorToColor([NSColor windowFrameTextColor]); - break; - } - - if (!color.isValid()) - color = RenderTheme::systemColor(cssValueId); - - if (color.isValid()) - m_systemColorCache.set(cssValueId, color.rgb()); - - return color; -} - -bool RenderThemeMac::usesTestModeFocusRingColor() const -{ - return WebCore::usesTestModeFocusRingColor(); } NSView* RenderThemeMac::documentViewFor(RenderObject* o) const { -#if PLATFORM(MAC) return ThemeMac::ensuredView(o->view()->frameView()); -#else - ASSERT_NOT_REACHED(); - return 0; -#endif -} - -bool RenderThemeMac::isControlStyled(const RenderStyle* style, const BorderData& border, - const FillLayer& background, const Color& backgroundColor) const -{ - if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart) - return style->border() != border; - - // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when - // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style - // adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming - // is in effect we treat it like the control is styled. - if (style->appearance() == MenulistPart && style->effectiveZoom() != 1.0f) - return true; - - return RenderTheme::isControlStyled(style, border, background, backgroundColor); -} - -void RenderThemeMac::adjustRepaintRect(const RenderObject* o, IntRect& r) -{ - ControlPart part = o->style()->appearance(); - -#if USE(NEW_THEME) - switch (part) { - case CheckboxPart: - case RadioPart: - case PushButtonPart: - case SquareButtonPart: - case DefaultButtonPart: - case ButtonPart: - case InnerSpinButtonPart: - return RenderTheme::adjustRepaintRect(o, r); - default: - break; - } -#endif - - float zoomLevel = o->style()->effectiveZoom(); - - if (part == MenulistPart) { - setPopupButtonCellState(o, r); - IntSize size = popupButtonSizes()[[popupButton() controlSize]]; - size.setHeight(size.height() * zoomLevel); - size.setWidth(r.width()); - r = inflateRect(r, size, popupButtonMargins(), zoomLevel); - } -} - -IntRect RenderThemeMac::inflateRect(const IntRect& r, const IntSize& size, const int* margins, float zoomLevel) const -{ - // Only do the inflation if the available width/height are too small. Otherwise try to - // fit the glow/check space into the available box's width/height. - int widthDelta = r.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel); - int heightDelta = r.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel); - IntRect result(r); - if (widthDelta < 0) { - result.setX(result.x() - margins[leftMargin] * zoomLevel); - result.setWidth(result.width() - widthDelta); - } - if (heightDelta < 0) { - result.setY(result.y() - margins[topMargin] * zoomLevel); - result.setHeight(result.height() - heightDelta); - } - return result; -} - -FloatRect RenderThemeMac::convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const -{ - FloatRect partRect(inputRect); - - // Compute an offset between the part renderer and the input renderer - FloatSize offsetFromInputRenderer; - const RenderObject* renderer = partRenderer; - while (renderer && renderer != inputRenderer) { - RenderObject* containingRenderer = renderer->container(); - offsetFromInputRenderer -= roundedIntSize(renderer->offsetFromContainer(containingRenderer, LayoutPoint())); - renderer = containingRenderer; - } - // If the input renderer was not a container, something went wrong - ASSERT(renderer == inputRenderer); - // Move the rect into partRenderer's coords - partRect.move(offsetFromInputRenderer); - // Account for the local drawing offset (tx, ty) - partRect.move(r.x(), r.y()); - - return partRect; -} - -void RenderThemeMac::updateCheckedState(NSCell* cell, const RenderObject* o) -{ - bool oldIndeterminate = [cell state] == NSMixedState; - bool indeterminate = isIndeterminate(o); - bool checked = isChecked(o); - - if (oldIndeterminate != indeterminate) { - [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)]; - return; - } - - bool oldChecked = [cell state] == NSOnState; - if (checked != oldChecked) - [cell setState:checked ? NSOnState : NSOffState]; -} - -void RenderThemeMac::updateEnabledState(NSCell* cell, const RenderObject* o) -{ - bool oldEnabled = [cell isEnabled]; - bool enabled = isEnabled(o); - if (enabled != oldEnabled) - [cell setEnabled:enabled]; -} - -void RenderThemeMac::updateFocusedState(NSCell* cell, const RenderObject* o) -{ - bool oldFocused = [cell showsFirstResponder]; - bool focused = isFocused(o) && o->style()->outlineStyleIsAuto(); - if (focused != oldFocused) - [cell setShowsFirstResponder:focused]; -} - -void RenderThemeMac::updatePressedState(NSCell* cell, const RenderObject* o) -{ - bool oldPressed = [cell isHighlighted]; - bool pressed = (o->node() && o->node()->active()); - if (pressed != oldPressed) - [cell setHighlighted:pressed]; -} - -bool RenderThemeMac::controlSupportsTints(const RenderObject* o) const -{ - // An alternate way to implement this would be to get the appropriate cell object - // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of - // that would be that we would match AppKit behavior more closely, but a disadvantage - // would be that we would rely on an AppKit SPI method. - - if (!isEnabled(o)) - return false; - - // Checkboxes only have tint when checked. - if (o->style()->appearance() == CheckboxPart) - return isChecked(o); - - // For now assume other controls have tint if enabled. - return true; -} - -NSControlSize RenderThemeMac::controlSizeForFont(RenderStyle* style) const -{ - int fontSize = style->fontSize(); - if (fontSize >= 16) - return NSRegularControlSize; - if (fontSize >= 11) - return NSSmallControlSize; - return NSMiniControlSize; -} - -void RenderThemeMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel) -{ - NSControlSize size; - if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel) && - minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel)) - size = NSRegularControlSize; - else if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel) && - minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel)) - size = NSSmallControlSize; - else - size = NSMiniControlSize; - if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same. - [cell setControlSize:size]; -} - -IntSize RenderThemeMac::sizeForFont(RenderStyle* style, const IntSize* sizes) const -{ - if (style->effectiveZoom() != 1.0f) { - IntSize result = sizes[controlSizeForFont(style)]; - return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom()); - } - return sizes[controlSizeForFont(style)]; -} - -IntSize RenderThemeMac::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const -{ - if (style->effectiveZoom() != 1.0f) { - IntSize result = sizes[controlSizeForSystemFont(style)]; - return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom()); - } - return sizes[controlSizeForSystemFont(style)]; -} - -void RenderThemeMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const -{ - // FIXME: Check is flawed, since it doesn't take min-width/max-width into account. - IntSize size = sizeForFont(style, sizes); - if (style->width().isIntrinsicOrAuto() && size.width() > 0) - style->setWidth(Length(size.width(), Fixed)); - if (style->height().isAuto() && size.height() > 0) - style->setHeight(Length(size.height(), Fixed)); -} - -void RenderThemeMac::setFontFromControlSize(StyleResolver*, RenderStyle* style, NSControlSize controlSize) const -{ - FontDescription fontDescription; - fontDescription.setIsAbsoluteSize(true); - fontDescription.setGenericFamily(FontDescription::SerifFamily); - - NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]]; - fontDescription.firstFamily().setFamily([font familyName]); - fontDescription.setComputedSize([font pointSize] * style->effectiveZoom()); - fontDescription.setSpecifiedSize([font pointSize] * style->effectiveZoom()); - - // Reset line height - style->setLineHeight(RenderStyle::initialLineHeight()); - - if (style->setFontDescription(fontDescription)) - style->font().update(0); -} - -NSControlSize RenderThemeMac::controlSizeForSystemFont(RenderStyle* style) const -{ - int fontSize = style->fontSize(); - if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize]) - return NSRegularControlSize; - if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize]) - return NSSmallControlSize; - return NSMiniControlSize; -} - -bool RenderThemeMac::paintTextField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) -{ - LocalCurrentGraphicsContext localContext(paintInfo.context); - -#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 - bool useNSTextFieldCell = o->style()->hasAppearance() - && o->style()->visitedDependentColor(CSSPropertyBackgroundColor) == Color::white - && !o->style()->hasBackgroundImage(); - - // We do not use NSTextFieldCell to draw styled text fields on Lion and SnowLeopard because - // there are a number of bugs on those platforms that require NSTextFieldCell to be in charge - // of painting its own background. We need WebCore to paint styled backgrounds, so we'll use - // this WebCoreSystemInterface function instead. - if (!useNSTextFieldCell) { - wkDrawBezeledTextFieldCell(r, isEnabled(o) && !isReadOnlyControl(o)); - return false; - } -#endif - - NSTextFieldCell *textField = this->textField(); - - GraphicsContextStateSaver stateSaver(*paintInfo.context); - - [textField setEnabled:(isEnabled(o) && !isReadOnlyControl(o))]; - [textField drawWithFrame:NSRect(r) inView:documentViewFor(o)]; - - [textField setControlView:nil]; - - return false; -} - -void RenderThemeMac::adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const -{ -} - -bool RenderThemeMac::paintCapsLockIndicator(RenderObject*, const PaintInfo& paintInfo, const IntRect& r) -{ - if (paintInfo.context->paintingDisabled()) - return true; - - LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawCapsLockIndicator(localContext.cgContext(), r); - - return false; -} - -bool RenderThemeMac::paintTextArea(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) -{ - LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawBezeledTextArea(r, isEnabled(o) && !isReadOnlyControl(o)); - return false; -} - -void RenderThemeMac::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const -{ -} - -const int* RenderThemeMac::popupButtonMargins() const -{ - static const int margins[3][4] = - { - { 0, 3, 1, 3 }, - { 0, 3, 2, 3 }, - { 0, 1, 0, 1 } - }; - return margins[[popupButton() controlSize]]; -} - -const IntSize* RenderThemeMac::popupButtonSizes() const -{ - static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; - return sizes; -} - -const int* RenderThemeMac::popupButtonPadding(NSControlSize size) const -{ - static const int padding[3][4] = - { - { 2, 26, 3, 8 }, - { 2, 23, 3, 8 }, - { 2, 22, 3, 10 } - }; - return padding[size]; -} - -bool RenderThemeMac::paintMenuList(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) -{ - LocalCurrentGraphicsContext localContext(paintInfo.context); - setPopupButtonCellState(o, r); - - NSPopUpButtonCell* popupButton = this->popupButton(); - - float zoomLevel = o->style()->effectiveZoom(); - IntSize size = popupButtonSizes()[[popupButton controlSize]]; - size.setHeight(size.height() * zoomLevel); - size.setWidth(r.width()); - - // Now inflate it to account for the shadow. - IntRect inflatedRect = r; - if (r.width() >= minimumMenuListSize(o->style())) - inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel); - - GraphicsContextStateSaver stateSaver(*paintInfo.context); - - // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect - paintInfo.context->clip(inflatedRect); - - if (zoomLevel != 1.0f) { - inflatedRect.setWidth(inflatedRect.width() / zoomLevel); - inflatedRect.setHeight(inflatedRect.height() / zoomLevel); - paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); - paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); - } - - NSView *view = documentViewFor(o); - [popupButton drawWithFrame:inflatedRect inView:view]; -#if !BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING - if (isFocused(o) && o->style()->outlineStyleIsAuto()) - [popupButton _web_drawFocusRingWithFrame:inflatedRect inView:view]; -#endif - [popupButton setControlView:nil]; - - return false; -} - -#if ENABLE(METER_ELEMENT) - -IntSize RenderThemeMac::meterSizeForBounds(const RenderMeter* renderMeter, const IntRect& bounds) const -{ - if (NoControlPart == renderMeter->style()->appearance()) - return bounds.size(); - - NSLevelIndicatorCell* cell = levelIndicatorFor(renderMeter); - // Makes enough room for cell's intrinsic size. - NSSize cellSize = [cell cellSizeForBounds:IntRect(IntPoint(), bounds.size())]; - return IntSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(), - bounds.height() < cellSize.height ? cellSize.height : bounds.height()); -} - -bool RenderThemeMac::paintMeter(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) -{ - if (!renderObject->isMeter()) - return true; - - LocalCurrentGraphicsContext localContext(paintInfo.context); - - NSLevelIndicatorCell* cell = levelIndicatorFor(toRenderMeter(renderObject)); - GraphicsContextStateSaver stateSaver(*paintInfo.context); - - [cell drawWithFrame:rect inView:documentViewFor(renderObject)]; - [cell setControlView:nil]; - return false; -} - -bool RenderThemeMac::supportsMeter(ControlPart part) const -{ - switch (part) { - case RelevancyLevelIndicatorPart: - case DiscreteCapacityLevelIndicatorPart: - case RatingLevelIndicatorPart: - case MeterPart: - case ContinuousCapacityLevelIndicatorPart: - return true; - default: - return false; - } -} - -NSLevelIndicatorStyle RenderThemeMac::levelIndicatorStyleFor(ControlPart part) const -{ - switch (part) { - case RelevancyLevelIndicatorPart: - return NSRelevancyLevelIndicatorStyle; - case DiscreteCapacityLevelIndicatorPart: - return NSDiscreteCapacityLevelIndicatorStyle; - case RatingLevelIndicatorPart: - return NSRatingLevelIndicatorStyle; - case MeterPart: - case ContinuousCapacityLevelIndicatorPart: - default: - return NSContinuousCapacityLevelIndicatorStyle; - } - -} - -NSLevelIndicatorCell* RenderThemeMac::levelIndicatorFor(const RenderMeter* renderMeter) const -{ - RenderStyle* style = renderMeter->style(); - ASSERT(style->appearance() != NoControlPart); - - if (!m_levelIndicator) - m_levelIndicator.adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]); - NSLevelIndicatorCell* cell = m_levelIndicator.get(); - - HTMLMeterElement* element = renderMeter->meterElement(); - double value = element->value(); - - // Because NSLevelIndicatorCell does not support optimum-in-the-middle type coloring, - // we explicitly control the color instead giving low and high value to NSLevelIndicatorCell as is. - switch (element->gaugeRegion()) { - case HTMLMeterElement::GaugeRegionOptimum: - // Make meter the green - [cell setWarningValue:value + 1]; - [cell setCriticalValue:value + 2]; - break; - case HTMLMeterElement::GaugeRegionSuboptimal: - // Make the meter yellow - [cell setWarningValue:value - 1]; - [cell setCriticalValue:value + 1]; - break; - case HTMLMeterElement::GaugeRegionEvenLessGood: - // Make the meter red - [cell setWarningValue:value - 2]; - [cell setCriticalValue:value - 1]; - break; - } - - [cell setLevelIndicatorStyle:levelIndicatorStyleFor(style->appearance())]; - [cell setBaseWritingDirection:style->isLeftToRightDirection() ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft]; - [cell setMinValue:element->min()]; - [cell setMaxValue:element->max()]; - RetainPtr<NSNumber> valueObject = [NSNumber numberWithDouble:value]; - [cell setObjectValue:valueObject.get()]; - - return cell; -} - -#endif - -#if ENABLE(PROGRESS_ELEMENT) -const IntSize* RenderThemeMac::progressBarSizes() const -{ - static const IntSize sizes[3] = { IntSize(0, 20), IntSize(0, 12), IntSize(0, 12) }; - return sizes; -} - -const int* RenderThemeMac::progressBarMargins(NSControlSize controlSize) const -{ - static const int margins[3][4] = - { - { 0, 0, 1, 0 }, - { 0, 0, 1, 0 }, - { 0, 0, 1, 0 }, - }; - return margins[controlSize]; -} - -int RenderThemeMac::minimumProgressBarHeight(RenderStyle* style) const -{ - return sizeForSystemFont(style, progressBarSizes()).height(); -} - -double RenderThemeMac::animationRepeatIntervalForProgressBar(RenderProgress*) const -{ - return progressAnimationFrameRate; -} - -double RenderThemeMac::animationDurationForProgressBar(RenderProgress*) const -{ - return progressAnimationNumFrames * progressAnimationFrameRate; -} - -void RenderThemeMac::adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const -{ -} - -bool RenderThemeMac::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) -{ - if (!renderObject->isProgress()) - return true; - - float zoomLevel = renderObject->style()->effectiveZoom(); - int controlSize = controlSizeForFont(renderObject->style()); - IntSize size = progressBarSizes()[controlSize]; - size.setHeight(size.height() * zoomLevel); - size.setWidth(rect.width()); - - // Now inflate it to account for the shadow. - IntRect inflatedRect = rect; - if (rect.height() <= minimumProgressBarHeight(renderObject->style())) - inflatedRect = inflateRect(inflatedRect, size, progressBarMargins(controlSize), zoomLevel); - - RenderProgress* renderProgress = toRenderProgress(renderObject); - HIThemeTrackDrawInfo trackInfo; - trackInfo.version = 0; - if (controlSize == NSRegularControlSize) - trackInfo.kind = renderProgress->position() < 0 ? kThemeLargeIndeterminateBar : kThemeLargeProgressBar; - else - trackInfo.kind = renderProgress->position() < 0 ? kThemeMediumIndeterminateBar : kThemeMediumProgressBar; - - trackInfo.bounds = IntRect(IntPoint(), inflatedRect.size()); - trackInfo.min = 0; - trackInfo.max = numeric_limits<SInt32>::max(); - trackInfo.value = lround(renderProgress->position() * nextafter(trackInfo.max, 0)); - trackInfo.trackInfo.progress.phase = lround(renderProgress->animationProgress() * nextafter(progressAnimationNumFrames, 0)); - trackInfo.attributes = kThemeTrackHorizontal; - trackInfo.enableState = isActive(renderObject) ? kThemeTrackActive : kThemeTrackInactive; - trackInfo.reserved = 0; - trackInfo.filler1 = 0; - - OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(inflatedRect.size(), 1); - if (!imageBuffer) - return true; - - ContextContainer cgContextContainer(imageBuffer->context()); - CGContextRef cgContext = cgContextContainer.context(); - HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal); - - GraphicsContextStateSaver stateSaver(*paintInfo.context); - - if (!renderProgress->style()->isLeftToRightDirection()) { - paintInfo.context->translate(2 * inflatedRect.x() + inflatedRect.width(), 0); - paintInfo.context->scale(FloatSize(-1, 1)); - } - - paintInfo.context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, inflatedRect.location()); - return false; -} -#endif - -const float baseFontSize = 11.0f; -const float baseArrowHeight = 4.0f; -const float baseArrowWidth = 5.0f; -const float baseSpaceBetweenArrows = 2.0f; -const int arrowPaddingLeft = 6; -const int arrowPaddingRight = 6; -const int paddingBeforeSeparator = 4; -const int baseBorderRadius = 5; -const int styledPopupPaddingLeft = 8; -const int styledPopupPaddingTop = 1; -const int styledPopupPaddingBottom = 2; - -static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) -{ - static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f }; - static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f }; - float a = inData[0]; - int i = 0; - for (i = 0; i < 4; i++) - outData[i] = (1.0f - a) * dark[i] + a * light[i]; -} - -static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) -{ - static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f }; - static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f }; - float a = inData[0]; - int i = 0; - for (i = 0; i < 4; i++) - outData[i] = (1.0f - a) * dark[i] + a * light[i]; -} - -static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) -{ - static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f }; - static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - float a = inData[0]; - int i = 0; - for (i = 0; i < 4; i++) - outData[i] = (1.0f - a) * dark[i] + a * light[i]; -} - -static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) -{ - static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f }; - static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f }; - float a = inData[0]; - int i = 0; - for (i = 0; i < 4; i++) - outData[i] = (1.0f - a) * dark[i] + a * light[i]; -} - -void RenderThemeMac::paintMenuListButtonGradients(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) -{ - if (r.isEmpty()) - return; - - ContextContainer cgContextContainer(paintInfo.context); - CGContextRef context = cgContextContainer.context(); - - GraphicsContextStateSaver stateSaver(*paintInfo.context); - - RoundedRect border = o->style()->getRoundedBorderFor(r, o->view()); - int radius = border.radii().topLeft().width(); - - CGColorSpaceRef cspace = deviceRGBColorSpaceRef(); - - FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f); - struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL }; - RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks)); - RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false)); - - FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f); - struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL }; - RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks)); - RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false)); - - struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL }; - RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); - RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false)); - - RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false)); - - RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false)); - - { - GraphicsContextStateSaver stateSaver(*paintInfo.context); - CGContextClipToRect(context, r); - paintInfo.context->addRoundedRectClip(border); - context = cgContextContainer.context(); - CGContextDrawShading(context, mainShading.get()); - } - - { - GraphicsContextStateSaver stateSaver(*paintInfo.context); - CGContextClipToRect(context, topGradient); - paintInfo.context->addRoundedRectClip(RoundedRect(enclosingIntRect(topGradient), border.radii().topLeft(), border.radii().topRight(), IntSize(), IntSize())); - context = cgContextContainer.context(); - CGContextDrawShading(context, topShading.get()); - } - - if (!bottomGradient.isEmpty()) { - GraphicsContextStateSaver stateSaver(*paintInfo.context); - CGContextClipToRect(context, bottomGradient); - paintInfo.context->addRoundedRectClip(RoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), border.radii().bottomLeft(), border.radii().bottomRight())); - context = cgContextContainer.context(); - CGContextDrawShading(context, bottomShading.get()); - } - - { - GraphicsContextStateSaver stateSaver(*paintInfo.context); - CGContextClipToRect(context, r); - paintInfo.context->addRoundedRectClip(border); - context = cgContextContainer.context(); - CGContextDrawShading(context, leftShading.get()); - CGContextDrawShading(context, rightShading.get()); - } -} - -bool RenderThemeMac::paintMenuListButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) -{ - IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(), - r.y() + o->style()->borderTopWidth(), - r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(), - r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth()); - // Draw the gradients to give the styled popup menu a button appearance - paintMenuListButtonGradients(o, paintInfo, bounds); - - // Since we actually know the size of the control here, we restrict the font scale to make sure the arrows will fit vertically in the bounds - float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows)); - float centerY = bounds.y() + bounds.height() / 2.0f; - float arrowHeight = baseArrowHeight * fontScale; - float arrowWidth = baseArrowWidth * fontScale; - float leftEdge = bounds.maxX() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth; - float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale; - - if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom()) - return false; - - GraphicsContextStateSaver stateSaver(*paintInfo.context); - - paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), o->style()->colorSpace()); - paintInfo.context->setStrokeStyle(NoStroke); - - FloatPoint arrow1[3]; - arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f); - arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f); - arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight); - - // Draw the top arrow - paintInfo.context->drawConvexPolygon(3, arrow1, true); - - FloatPoint arrow2[3]; - arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f); - arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f); - arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight); - - // Draw the bottom arrow - paintInfo.context->drawConvexPolygon(3, arrow2, true); - - Color leftSeparatorColor(0, 0, 0, 40); - Color rightSeparatorColor(255, 255, 255, 40); - - // FIXME: Should the separator thickness and space be scaled up by fontScale? - int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin. - int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * o->style()->effectiveZoom()); // FIXME: Round? - - // Draw the separator to the left of the arrows - paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin. - paintInfo.context->setStrokeStyle(SolidStroke); - paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB); - paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()), - IntPoint(leftEdgeOfSeparator, bounds.maxY())); - - paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB); - paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()), - IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY())); - return false; -} - -static const IntSize* menuListButtonSizes() -{ - static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; - return sizes; -} - -void RenderThemeMac::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const -{ - NSControlSize controlSize = controlSizeForFont(style); - - style->resetBorder(); - style->resetPadding(); - - // Height is locked to auto. - style->setHeight(Length(Auto)); - - // White-space is locked to pre - style->setWhiteSpace(PRE); - - // Set the foreground color to black or gray when we have the aqua look. - // Cast to RGB32 is to work around a compiler bug. - style->setColor(e && e->isEnabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray); - - // Set the button's vertical size. - setSizeFromFont(style, menuListButtonSizes()); - - // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out - // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate - // system font for the control size instead. - setFontFromControlSize(styleResolver, style, controlSize); - - style->setBoxShadow(nullptr); -} - -int RenderThemeMac::popupInternalPaddingLeft(RenderStyle* style) const -{ - if (style->appearance() == MenulistPart) - return popupButtonPadding(controlSizeForFont(style))[leftPadding] * style->effectiveZoom(); - if (style->appearance() == MenulistButtonPart) - return styledPopupPaddingLeft * style->effectiveZoom(); - return 0; -} - -int RenderThemeMac::popupInternalPaddingRight(RenderStyle* style) const -{ - if (style->appearance() == MenulistPart) - return popupButtonPadding(controlSizeForFont(style))[rightPadding] * style->effectiveZoom(); - if (style->appearance() == MenulistButtonPart) { - float fontScale = style->fontSize() / baseFontSize; - float arrowWidth = baseArrowWidth * fontScale; - return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom())); - } - return 0; -} - -int RenderThemeMac::popupInternalPaddingTop(RenderStyle* style) const -{ - if (style->appearance() == MenulistPart) - return popupButtonPadding(controlSizeForFont(style))[topPadding] * style->effectiveZoom(); - if (style->appearance() == MenulistButtonPart) - return styledPopupPaddingTop * style->effectiveZoom(); - return 0; -} - -int RenderThemeMac::popupInternalPaddingBottom(RenderStyle* style) const -{ - if (style->appearance() == MenulistPart) - return popupButtonPadding(controlSizeForFont(style))[bottomPadding] * style->effectiveZoom(); - if (style->appearance() == MenulistButtonPart) - return styledPopupPaddingBottom * style->effectiveZoom(); - return 0; -} - -void RenderThemeMac::adjustMenuListButtonStyle(StyleResolver*, RenderStyle* style, Element*) const -{ - float fontScale = style->fontSize() / baseFontSize; - - style->resetPadding(); - style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up? - - const int minHeight = 15; - style->setMinHeight(Length(minHeight, Fixed)); - - style->setLineHeight(RenderStyle::initialLineHeight()); -} - -void RenderThemeMac::setPopupButtonCellState(const RenderObject* o, const IntRect& r) -{ - NSPopUpButtonCell* popupButton = this->popupButton(); - - // Set the control size based off the rectangle we're painting into. - setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom()); - - // Update the various states we respond to. - updateActiveState(popupButton, o); - updateCheckedState(popupButton, o); - updateEnabledState(popupButton, o); - updatePressedState(popupButton, o); -#if BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING - updateFocusedState(popupButton, o); -#endif -} - -const IntSize* RenderThemeMac::menuListSizes() const -{ - static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) }; - return sizes; -} - -int RenderThemeMac::minimumMenuListSize(RenderStyle* style) const -{ - return sizeForSystemFont(style, menuListSizes()).width(); -} - -const int trackWidth = 5; -const int trackRadius = 2; - -void RenderThemeMac::adjustSliderTrackStyle(StyleResolver*, RenderStyle* style, Element*) const -{ - style->setBoxShadow(nullptr); -} - -bool RenderThemeMac::paintSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) -{ - IntRect bounds = r; - float zoomLevel = o->style()->effectiveZoom(); - float zoomedTrackWidth = trackWidth * zoomLevel; - - if (o->style()->appearance() == SliderHorizontalPart || o->style()->appearance() == MediaSliderPart) { - bounds.setHeight(zoomedTrackWidth); - bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2); - } else if (o->style()->appearance() == SliderVerticalPart) { - bounds.setWidth(zoomedTrackWidth); - bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2); - } - - LocalCurrentGraphicsContext localContext(paintInfo.context); - CGContextRef context = localContext.cgContext(); - CGColorSpaceRef cspace = deviceRGBColorSpaceRef(); - -#if ENABLE(DATALIST_ELEMENT) - paintSliderTicks(o, paintInfo, r); -#endif - - GraphicsContextStateSaver stateSaver(*paintInfo.context); - CGContextClipToRect(context, bounds); - - struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL }; - RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); - RetainPtr<CGShadingRef> mainShading; - if (o->style()->appearance() == SliderVerticalPart) - mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.maxY()), CGPointMake(bounds.maxX(), bounds.maxY()), mainFunction.get(), false, false)); - else - mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.maxY()), mainFunction.get(), false, false)); - - IntSize radius(trackRadius, trackRadius); - paintInfo.context->addRoundedRectClip(RoundedRect(bounds, radius, radius, radius, radius)); - context = localContext.cgContext(); - CGContextDrawShading(context, mainShading.get()); - - return false; -} - -void RenderThemeMac::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const -{ - RenderTheme::adjustSliderThumbStyle(styleResolver, style, element); - style->setBoxShadow(nullptr); -} - -const float verticalSliderHeightPadding = 0.1f; - -bool RenderThemeMac::paintSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) -{ - NSSliderCell* sliderThumbCell = o->style()->appearance() == SliderThumbVerticalPart - ? sliderThumbVertical() - : sliderThumbHorizontal(); - - LocalCurrentGraphicsContext localContext(paintInfo.context); - - // Update the various states we respond to. - updateActiveState(sliderThumbCell, o); - updateEnabledState(sliderThumbCell, o); - updateFocusedState(sliderThumbCell, (o->node() && o->node()->focusDelegate()->renderer()) ? o->node()->focusDelegate()->renderer() : o); - - // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it. - bool oldPressed; - if (o->style()->appearance() == SliderThumbVerticalPart) - oldPressed = m_isSliderThumbVerticalPressed; - else - oldPressed = m_isSliderThumbHorizontalPressed; - - bool pressed = isPressed(o); - - if (o->style()->appearance() == SliderThumbVerticalPart) - m_isSliderThumbVerticalPressed = pressed; - else - m_isSliderThumbHorizontalPressed = pressed; - - if (pressed != oldPressed) { - if (pressed) - [sliderThumbCell startTrackingAt:NSPoint() inView:nil]; - else - [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES]; - } - - FloatRect bounds = r; - // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider. - if (o->style()->appearance() == SliderThumbVerticalPart) - bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o->style()->effectiveZoom()); - - GraphicsContextStateSaver stateSaver(*paintInfo.context); - float zoomLevel = o->style()->effectiveZoom(); - - FloatRect unzoomedRect = bounds; - if (zoomLevel != 1.0f) { - unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); - unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); - paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); - paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); - } - -#if PLATFORM(CHROMIUM) - paintInfo.context->translate(0, unzoomedRect.y()); - paintInfo.context->scale(FloatSize(1, -1)); - paintInfo.context->translate(0, -(unzoomedRect.y() + unzoomedRect.height())); -#endif - - [sliderThumbCell drawInteriorWithFrame:unzoomedRect inView:documentViewFor(o)]; - [sliderThumbCell setControlView:nil]; - - return false; -} - -bool RenderThemeMac::paintSearchField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) -{ - LocalCurrentGraphicsContext localContext(paintInfo.context); - NSSearchFieldCell* search = this->search(); - - setSearchCellState(o, r); - - GraphicsContextStateSaver stateSaver(*paintInfo.context); - - float zoomLevel = o->style()->effectiveZoom(); - - IntRect unzoomedRect = r; - - if (zoomLevel != 1.0f) { - unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); - unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); - paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); - paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); - } - - // Set the search button to nil before drawing. Then reset it so we can draw it later. - [search setSearchButtonCell:nil]; - - [search drawWithFrame:NSRect(unzoomedRect) inView:documentViewFor(o)]; - - [search setControlView:nil]; - [search resetSearchButtonCell]; - - return false; -} - -void RenderThemeMac::setSearchCellState(RenderObject* o, const IntRect&) -{ - NSSearchFieldCell* search = this->search(); - - [search setControlSize:controlSizeForFont(o->style())]; - - // Update the various states we respond to. - updateActiveState(search, o); - updateEnabledState(search, o); - updateFocusedState(search, o); -} - -const IntSize* RenderThemeMac::searchFieldSizes() const -{ - static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) }; - return sizes; -} - -void RenderThemeMac::setSearchFieldSize(RenderStyle* style) const -{ - // If the width and height are both specified, then we have nothing to do. - if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) - return; - - // Use the font size to determine the intrinsic width of the control. - setSizeFromFont(style, searchFieldSizes()); -} - -void RenderThemeMac::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element*) const -{ - // Override border. - style->resetBorder(); - const short borderWidth = 2 * style->effectiveZoom(); - style->setBorderLeftWidth(borderWidth); - style->setBorderLeftStyle(INSET); - style->setBorderRightWidth(borderWidth); - style->setBorderRightStyle(INSET); - style->setBorderBottomWidth(borderWidth); - style->setBorderBottomStyle(INSET); - style->setBorderTopWidth(borderWidth); - style->setBorderTopStyle(INSET); - - // Override height. - style->setHeight(Length(Auto)); - setSearchFieldSize(style); - - // Override padding size to match AppKit text positioning. - const int padding = 1 * style->effectiveZoom(); - style->setPaddingLeft(Length(padding, Fixed)); - style->setPaddingRight(Length(padding, Fixed)); - style->setPaddingTop(Length(padding, Fixed)); - style->setPaddingBottom(Length(padding, Fixed)); - - NSControlSize controlSize = controlSizeForFont(style); - setFontFromControlSize(styleResolver, style, controlSize); - - style->setBoxShadow(nullptr); -} - -bool RenderThemeMac::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) -{ - Element* input = o->node()->shadowHost(); - if (!input) - input = toElement(o->node()); - - if (!input->renderer()->isBox()) - return false; - - LocalCurrentGraphicsContext localContext(paintInfo.context); - setSearchCellState(input->renderer(), r); - - NSSearchFieldCell* search = this->search(); - - if (input->isEnabledFormControl() && (input->isTextFormControl() && !static_cast<HTMLTextFormControlElement*>(input)->readOnly())) { - updateActiveState([search cancelButtonCell], o); - updatePressedState([search cancelButtonCell], o); - } - else if ([[search cancelButtonCell] isHighlighted]) - [[search cancelButtonCell] setHighlighted:NO]; - - GraphicsContextStateSaver stateSaver(*paintInfo.context); - - float zoomLevel = o->style()->effectiveZoom(); - - FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())]; - -#if ENABLE(INPUT_SPEECH) - // Take care of cases where the cancel button was not aligned with the right border of the input element (for e.g. - // when speech input is enabled for the input element. - IntRect absBoundingBox = input->renderer()->absoluteBoundingBoxRect(); - int absRight = absBoundingBox.x() + absBoundingBox.width() - input->renderBox()->paddingRight() - input->renderBox()->borderRight(); - int spaceToRightOfCancelButton = absRight - (r.x() + r.width()); - localBounds.setX(localBounds.x() - spaceToRightOfCancelButton); -#endif - - localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); - - FloatRect unzoomedRect(localBounds); - if (zoomLevel != 1.0f) { - unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); - unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); - paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); - paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); - } - - [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)]; - [[search cancelButtonCell] setControlView:nil]; - return false; -} - -const IntSize* RenderThemeMac::cancelButtonSizes() const -{ - static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) }; - return sizes; -} - -void RenderThemeMac::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const -{ - IntSize size = sizeForSystemFont(style, cancelButtonSizes()); - style->setWidth(Length(size.width(), Fixed)); - style->setHeight(Length(size.height(), Fixed)); - style->setBoxShadow(nullptr); -} - -const IntSize* RenderThemeMac::resultsButtonSizes() const -{ - static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) }; - return sizes; -} - -const int emptyResultsOffset = 9; -void RenderThemeMac::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const -{ - IntSize size = sizeForSystemFont(style, resultsButtonSizes()); - style->setWidth(Length(size.width() - emptyResultsOffset, Fixed)); - style->setHeight(Length(size.height(), Fixed)); - style->setBoxShadow(nullptr); -} - -bool RenderThemeMac::paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&) -{ - return false; -} - -void RenderThemeMac::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const -{ - IntSize size = sizeForSystemFont(style, resultsButtonSizes()); - style->setWidth(Length(size.width(), Fixed)); - style->setHeight(Length(size.height(), Fixed)); - style->setBoxShadow(nullptr); -} - -bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) -{ - Node* input = o->node()->shadowHost(); - if (!input) - input = o->node(); - if (!input->renderer()->isBox()) - return false; - - LocalCurrentGraphicsContext localContext(paintInfo.context); - setSearchCellState(input->renderer(), r); - - NSSearchFieldCell* search = this->search(); - - if ([search searchMenuTemplate] != nil) - [search setSearchMenuTemplate:nil]; - - updateActiveState([search searchButtonCell], o); - - FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())]; - localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); - - [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(o)]; - [[search searchButtonCell] setControlView:nil]; - return false; -} - -const int resultsArrowWidth = 5; -void RenderThemeMac::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const -{ - IntSize size = sizeForSystemFont(style, resultsButtonSizes()); - style->setWidth(Length(size.width() + resultsArrowWidth, Fixed)); - style->setHeight(Length(size.height(), Fixed)); - style->setBoxShadow(nullptr); -} - -bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) -{ - Node* input = o->node()->shadowHost(); - if (!input) - input = o->node(); - if (!input->renderer()->isBox()) - return false; - - LocalCurrentGraphicsContext localContext(paintInfo.context); - setSearchCellState(input->renderer(), r); - - NSSearchFieldCell* search = this->search(); - - updateActiveState([search searchButtonCell], o); - - if (![search searchMenuTemplate]) - [search setSearchMenuTemplate:searchMenuTemplate()]; - - GraphicsContextStateSaver stateSaver(*paintInfo.context); - float zoomLevel = o->style()->effectiveZoom(); - - FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())]; - localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); - - IntRect unzoomedRect(localBounds); - if (zoomLevel != 1.0f) { - unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); - unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); - paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); - paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); - } - - [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)]; - [[search searchButtonCell] setControlView:nil]; - - return false; } #if ENABLE(VIDEO) + typedef enum { MediaControllerThemeClassic = 1, MediaControllerThemeQuickTime = 2 @@ -1735,7 +75,7 @@ typedef enum { static int mediaControllerTheme() { static int controllerTheme = -1; - + if (controllerTheme != -1) return controllerTheme; @@ -1750,40 +90,10 @@ static int mediaControllerTheme() controllerTheme = MediaControllerThemeQuickTime; return controllerTheme; } -#endif - -#if ENABLE(DATALIST_ELEMENT) -IntSize RenderThemeMac::sliderTickSize() const -{ - return IntSize(1, 3); -} -int RenderThemeMac::sliderTickOffsetFromTrackCenter() const -{ - return -9; -} -#endif - -const int sliderThumbWidth = 15; -const int sliderThumbHeight = 15; const int mediaSliderThumbWidth = 13; const int mediaSliderThumbHeight = 14; -void RenderThemeMac::adjustSliderThumbSize(RenderStyle* style, Element*) const -{ - float zoomLevel = style->effectiveZoom(); - if (style->appearance() == SliderThumbHorizontalPart || style->appearance() == SliderThumbVerticalPart) { - style->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed)); - style->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed)); - } - -#if ENABLE(VIDEO) - adjustMediaSliderThumbSize(style); -#endif -} - -#if ENABLE(VIDEO) - void RenderThemeMac::adjustMediaSliderThumbSize(RenderStyle* style) const { int wkPart; @@ -1816,7 +126,7 @@ void RenderThemeMac::adjustMediaSliderThumbSize(RenderStyle* style) const style->setHeight(Length(static_cast<int>(height * zoomLevel), Fixed)); } -enum WKMediaControllerThemeState { +enum WKMediaControllerThemeState { MediaUIPartDisabledFlag = 1 << 0, MediaUIPartPressedFlag = 1 << 1, MediaUIPartDrawEndCapsFlag = 1 << 3, @@ -1848,7 +158,6 @@ static FloatRect getUnzoomedRectAndAdjustCurrentContext(RenderObject* o, const P return unzoomedRect; } - bool RenderThemeMac::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { Node* node = o->node(); @@ -1930,12 +239,12 @@ bool RenderThemeMac::paintMediaSliderTrack(RenderObject* o, const PaintInfo& pai float duration = mediaElement->duration(); if (isnan(duration)) duration = 0; - + ContextContainer cgContextContainer(paintInfo.context); CGContextRef context = cgContextContainer.context(); GraphicsContextStateSaver stateSaver(*paintInfo.context); FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r); - wkDrawMediaSliderTrack(mediaControllerTheme(), context, unzoomedRect, + wkDrawMediaSliderTrack(mediaControllerTheme(), context, unzoomedRect, timeLoaded, currentTime, duration, getMediaUIPartStateFlags(node)); return false; } @@ -1950,13 +259,13 @@ bool RenderThemeMac::paintMediaSliderThumb(RenderObject* o, const PaintInfo& pai wkDrawMediaUIPart(MediaSliderThumb, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node)); return false; } - + bool RenderThemeMac::paintMediaRewindButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { Node* node = o->node(); if (!node) return false; - + LocalCurrentGraphicsContext localContext(paintInfo.context); wkDrawMediaUIPart(MediaRewindButton, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node)); return false; @@ -1967,7 +276,7 @@ bool RenderThemeMac::paintMediaReturnToRealtimeButton(RenderObject* o, const Pai Node* node = o->node(); if (!node) return false; - + LocalCurrentGraphicsContext localContext(paintInfo.context); wkDrawMediaUIPart(MediaReturnToRealtimeButton, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node)); return false; @@ -1985,7 +294,7 @@ bool RenderThemeMac::paintMediaToggleClosedCaptionsButton(RenderObject* o, const wkDrawMediaUIPart(mediaControlElementType(node), mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node)); return false; } - + bool RenderThemeMac::paintMediaControlsBackground(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { Node* node = o->node(); @@ -2044,7 +353,7 @@ bool RenderThemeMac::paintMediaVolumeSliderTrack(RenderObject* o, const PaintInf wkDrawMediaUIPart(MediaVolumeSlider, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node)); return false; } - + bool RenderThemeMac::paintMediaVolumeSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { Node* node = o->node(); @@ -2061,7 +370,7 @@ bool RenderThemeMac::paintMediaFullScreenVolumeSliderTrack(RenderObject* o, cons Node* node = o->node(); if (!node) return false; - + LocalCurrentGraphicsContext localContext(paintInfo.context); wkDrawMediaUIPart(MediaFullScreenVolumeSlider, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node)); return false; @@ -2072,7 +381,7 @@ bool RenderThemeMac::paintMediaFullScreenVolumeSliderThumb(RenderObject* o, cons Node* node = o->node(); if (!node) return false; - + LocalCurrentGraphicsContext localContext(paintInfo.context); wkDrawMediaUIPart(MediaFullScreenVolumeSliderThumb, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node)); return false; @@ -2080,29 +389,19 @@ bool RenderThemeMac::paintMediaFullScreenVolumeSliderThumb(RenderObject* o, cons String RenderThemeMac::extraMediaControlsStyleSheet() { -#if PLATFORM(MAC) if (mediaControllerTheme() == MediaControllerThemeQuickTime) return String(mediaControlsQuickTimeUserAgentStyleSheet, sizeof(mediaControlsQuickTimeUserAgentStyleSheet)); return String(); -#else - ASSERT_NOT_REACHED(); - return String(); -#endif } #if ENABLE(FULLSCREEN_API) String RenderThemeMac::extraFullScreenStyleSheet() { -#if PLATFORM(MAC) if (mediaControllerTheme() == MediaControllerThemeQuickTime) return String(fullscreenQuickTimeUserAgentStyleSheet, sizeof(fullscreenQuickTimeUserAgentStyleSheet)); - - return String(); -#else - ASSERT_NOT_REACHED(); + return String(); -#endif } #endif @@ -2131,145 +430,4 @@ IntPoint RenderThemeMac::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonB #endif // ENABLE(VIDEO) -bool RenderThemeMac::shouldShowPlaceholderWhenFocused() const -{ -#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 - return true; -#else - return false; -#endif -} - -NSPopUpButtonCell* RenderThemeMac::popupButton() const -{ - if (!m_popupButton) { - m_popupButton.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]); - [m_popupButton.get() setUsesItemFromMenu:NO]; - [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior]; - } - - return m_popupButton.get(); -} - -NSSearchFieldCell* RenderThemeMac::search() const -{ - if (!m_search) { - m_search.adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]); - [m_search.get() setBezelStyle:NSTextFieldRoundedBezel]; - [m_search.get() setBezeled:YES]; - [m_search.get() setEditable:YES]; - [m_search.get() setFocusRingType:NSFocusRingTypeExterior]; - } - - return m_search.get(); -} - -NSMenu* RenderThemeMac::searchMenuTemplate() const -{ - if (!m_searchMenuTemplate) - m_searchMenuTemplate.adoptNS([[NSMenu alloc] initWithTitle:@""]); - - return m_searchMenuTemplate.get(); -} - -NSSliderCell* RenderThemeMac::sliderThumbHorizontal() const -{ - if (!m_sliderThumbHorizontal) { - m_sliderThumbHorizontal.adoptNS([[NSSliderCell alloc] init]); - [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider]; - [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize]; - [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior]; - } - - return m_sliderThumbHorizontal.get(); -} - -NSSliderCell* RenderThemeMac::sliderThumbVertical() const -{ - if (!m_sliderThumbVertical) { - m_sliderThumbVertical.adoptNS([[NSSliderCell alloc] init]); - [m_sliderThumbVertical.get() setSliderType:NSLinearSlider]; - [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize]; - [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior]; - } - - return m_sliderThumbVertical.get(); -} - -NSTextFieldCell* RenderThemeMac::textField() const -{ - if (!m_textField) { - m_textField.adoptNS([[WebCoreTextFieldCell alloc] initTextCell:@""]); - [m_textField.get() setBezeled:YES]; - [m_textField.get() setEditable:YES]; - [m_textField.get() setFocusRingType:NSFocusRingTypeExterior]; -#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 - [m_textField.get() setDrawsBackground:YES]; - [m_textField.get() setBackgroundColor:[NSColor whiteColor]]; -#else - // Post-Lion, WebCore can be in charge of paintinng the background thanks to - // the workaround in place for <rdar://problem/11385461>, which is implemented - // above as _coreUIDrawOptionsWithFrame. - [m_textField.get() setDrawsBackground:NO]; -#endif - } - - return m_textField.get(); -} - -String RenderThemeMac::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const -{ - if (width <= 0) - return String(); - - String strToTruncate; - if (fileList->isEmpty()) - strToTruncate = fileListDefaultLabel(multipleFilesAllowed); - else if (fileList->length() == 1) - strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(fileList->item(0)->path())]; - else - return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks); - - return StringTruncator::centerTruncate(strToTruncate, width, font, StringTruncator::EnableRoundingHacks); -} - -void RenderThemeMac::paintPlugInSnapshotOverlay(RenderSnapshottedPlugIn* renderer, const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const -{ - LayoutUnit cWidth = renderer->contentWidth(); - LayoutUnit cHeight = renderer->contentHeight(); - if (!cWidth || !cHeight) - return; - - GraphicsContext* context = paintInfo.context; - GraphicsContextStateSaver saver(*context); - - LayoutSize borderAndPadding(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop()); - - LayoutSize contentSize(cWidth, cHeight); - LayoutPoint contentLocation = paintOffset; - contentLocation.move(borderAndPadding); - - RefPtr<Gradient> g = Gradient::create(contentLocation, FloatPoint(contentLocation.x(), contentLocation.y() + cHeight)); - g->addColorStop(0, Color(.5f, .5, .5, .7)); - g->addColorStop(.2, Color(.54f, .54, .54, .3)); - g->addColorStop(.6, Color(.62f, .62, .62, .3)); - g->addColorStop(1, Color(.7f, .7, .7, .95)); - context->setFillGradient(g.release()); - context->fillRect(pixelSnappedIntRect(LayoutRect(contentLocation, contentSize))); - - static const float diameter = 50, triangleRadius = 12; - LayoutPoint center = contentLocation; - center.move(cWidth / 2, cHeight / 2); - context->setFillColor(Color(.4f, .4, .4, .7), ColorSpaceSRGB); - context->fillEllipse(FloatRect(center.x() - diameter / 2, center.y() - diameter / 2, diameter, diameter)); - - Path p; - p.moveTo(FloatPoint(center.x() - triangleRadius * 3 / 4, center.y() - triangleRadius)); - p.addLineTo(FloatPoint(center.x() + triangleRadius * 5 / 4, center.y())); - p.addLineTo(FloatPoint(center.x() - triangleRadius * 3 / 4, center.y() + triangleRadius)); - p.closeSubpath(); - context->setFillColor(Color(1.f, 1.f, 1.f, .9f), ColorSpaceSRGB); - context->fillPath(p); -} - } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderThemeMacShared.h b/Source/WebCore/rendering/RenderThemeMacShared.h new file mode 100644 index 000000000..5283cb8db --- /dev/null +++ b/Source/WebCore/rendering/RenderThemeMacShared.h @@ -0,0 +1,227 @@ +/* + * This file is part of the theme implementation for form controls in WebCore. + * + * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef RenderThemeMacShared_h +#define RenderThemeMacShared_h + +#import "RenderTheme.h" +#import <wtf/HashMap.h> +#import <wtf/RetainPtr.h> + +OBJC_CLASS WebCoreRenderThemeNotificationObserver; + +namespace WebCore { + +class RenderProgress; +class RenderStyle; + +class RenderThemeMacShared : public RenderTheme { +public: + // A method asking if the control changes its tint when the window has focus or not. + virtual bool controlSupportsTints(const RenderObject*) const; + + // A general method asking if any control tinting is supported at all. + virtual bool supportsControlTints() const { return true; } + + virtual void adjustRepaintRect(const RenderObject*, IntRect&) OVERRIDE; + + virtual bool isControlStyled(const RenderStyle*, const BorderData&, const FillLayer&, const Color& backgroundColor) const; + + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveListBoxSelectionBackgroundColor() const; + virtual Color platformActiveListBoxSelectionForegroundColor() const; + virtual Color platformInactiveListBoxSelectionBackgroundColor() const; + virtual Color platformInactiveListBoxSelectionForegroundColor() const; + virtual Color platformFocusRingColor() const; + + virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return SmallScrollbar; } + + virtual void platformColorsDidChange(); + + // System fonts. + virtual void systemFont(int cssValueId, FontDescription&) const; + + virtual int minimumMenuListSize(RenderStyle*) const; + + virtual void adjustSliderThumbSize(RenderStyle*, Element*) const; + +#if ENABLE(DATALIST_ELEMENT) + virtual IntSize sliderTickSize() const OVERRIDE; + virtual int sliderTickOffsetFromTrackCenter() const OVERRIDE; +#endif + + virtual int popupInternalPaddingLeft(RenderStyle*) const; + virtual int popupInternalPaddingRight(RenderStyle*) const; + virtual int popupInternalPaddingTop(RenderStyle*) const; + virtual int popupInternalPaddingBottom(RenderStyle*) const; + + virtual bool paintCapsLockIndicator(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + + virtual bool popsMenuByArrowKeys() const OVERRIDE { return true; } + +#if ENABLE(METER_ELEMENT) + virtual IntSize meterSizeForBounds(const RenderMeter*, const IntRect&) const OVERRIDE; + virtual bool paintMeter(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool supportsMeter(ControlPart) const; +#endif + +#if ENABLE(PROGRESS_ELEMENT) + // Returns the repeat interval of the animation for the progress bar. + virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const; + // Returns the duration of the animation for the progress bar. + virtual double animationDurationForProgressBar(RenderProgress*) const; +#endif + + virtual Color systemColor(int cssValueId) const; + // Controls color values returned from platformFocusRingColor(). systemColor() will be used when false. + virtual bool usesTestModeFocusRingColor() const; + // A view associated to the contained document. Subclasses may not have such a view and return a fake. + virtual NSView* documentViewFor(RenderObject*) const = 0; + +protected: + RenderThemeMacShared(); + virtual ~RenderThemeMacShared(); + + virtual bool supportsSelectionForegroundColors() const { return false; } + + virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const; + + virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const; + + virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const; + + virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const; + +#if ENABLE(PROGRESS_ELEMENT) + virtual void adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&); +#endif + + virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSliderTrackStyle(StyleResolver*, RenderStyle*, Element*) const; + + virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSliderThumbStyle(StyleResolver*, RenderStyle*, Element*) const; + + virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const; + + virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&); + +#if ENABLE(VIDEO) + virtual void adjustMediaSliderThumbSize(RenderStyle*) const = 0; + virtual bool supportsClosedCaptioning() const { return true; } +#endif + + virtual bool shouldShowPlaceholderWhenFocused() const; + +private: + virtual String fileListNameForWidth(const FileList*, const Font&, int width, bool multipleFilesAllowed) const OVERRIDE; + + IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const; + + FloatRect convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect&) const; + + // Get the control size based off the font. Used by some of the controls (like buttons). + NSControlSize controlSizeForFont(RenderStyle*) const; + NSControlSize controlSizeForSystemFont(RenderStyle*) const; + void setControlSize(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel = 1.0f); + void setSizeFromFont(RenderStyle*, const IntSize* sizes) const; + IntSize sizeForFont(RenderStyle*, const IntSize* sizes) const; + IntSize sizeForSystemFont(RenderStyle*, const IntSize* sizes) const; + void setFontFromControlSize(StyleResolver*, RenderStyle*, NSControlSize) const; + + void updateCheckedState(NSCell*, const RenderObject*); + void updateEnabledState(NSCell*, const RenderObject*); + void updateFocusedState(NSCell*, const RenderObject*); + void updatePressedState(NSCell*, const RenderObject*); + // An optional hook for subclasses to update the control tint of NSCell. + virtual void updateActiveState(NSCell*, const RenderObject*) { } + + // Helpers for adjusting appearance and for painting + + void setPopupButtonCellState(const RenderObject*, const IntRect&); + const IntSize* popupButtonSizes() const; + const int* popupButtonMargins() const; + const int* popupButtonPadding(NSControlSize) const; + void paintMenuListButtonGradients(RenderObject*, const PaintInfo&, const IntRect&); + const IntSize* menuListSizes() const; + + const IntSize* searchFieldSizes() const; + const IntSize* cancelButtonSizes() const; + const IntSize* resultsButtonSizes() const; + void setSearchCellState(RenderObject*, const IntRect&); + void setSearchFieldSize(RenderStyle*) const; + + NSPopUpButtonCell* popupButton() const; + NSSearchFieldCell* search() const; + NSMenu* searchMenuTemplate() const; + NSSliderCell* sliderThumbHorizontal() const; + NSSliderCell* sliderThumbVertical() const; + NSTextFieldCell* textField() const; + +#if ENABLE(METER_ELEMENT) + NSLevelIndicatorStyle levelIndicatorStyleFor(ControlPart) const; + NSLevelIndicatorCell* levelIndicatorFor(const RenderMeter*) const; +#endif + +#if ENABLE(PROGRESS_ELEMENT) + int minimumProgressBarHeight(RenderStyle*) const; + const IntSize* progressBarSizes() const; + const int* progressBarMargins(NSControlSize) const; +#endif + +private: + mutable RetainPtr<NSPopUpButtonCell> m_popupButton; + mutable RetainPtr<NSSearchFieldCell> m_search; + mutable RetainPtr<NSMenu> m_searchMenuTemplate; + mutable RetainPtr<NSSliderCell> m_sliderThumbHorizontal; + mutable RetainPtr<NSSliderCell> m_sliderThumbVertical; + mutable RetainPtr<NSLevelIndicatorCell> m_levelIndicator; + mutable RetainPtr<NSTextFieldCell> m_textField; + + bool m_isSliderThumbHorizontalPressed; + bool m_isSliderThumbVerticalPressed; + + mutable HashMap<int, RGBA32> m_systemColorCache; + + RetainPtr<WebCoreRenderThemeNotificationObserver> m_notificationObserver; +}; + +} // namespace WebCore + +#endif // RenderThemeMacShared_h diff --git a/Source/WebCore/rendering/RenderThemeMacShared.mm b/Source/WebCore/rendering/RenderThemeMacShared.mm new file mode 100644 index 000000000..e6074cc26 --- /dev/null +++ b/Source/WebCore/rendering/RenderThemeMacShared.mm @@ -0,0 +1,1835 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * 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. + */ + +#import "config.h" +#import "RenderThemeMacShared.h" + +#import "BitmapImage.h" +#import "ColorMac.h" +#import "CSSValueList.h" +#import "CSSValueKeywords.h" +#import "Document.h" +#import "Element.h" +#import "FileList.h" +#import "FrameView.h" +#import "GraphicsContextCG.h" +#import "HTMLInputElement.h" +#import "HTMLMediaElement.h" +#import "HTMLNames.h" +#import "Image.h" +#import "ImageBuffer.h" +#import "LocalCurrentGraphicsContext.h" +#import "LocalizedStrings.h" +#import "MediaControlElements.h" +#import "PaintInfo.h" +#import "RenderMedia.h" +#import "RenderMediaControls.h" +#import "RenderSlider.h" +#import "RenderSnapshottedPlugIn.h" +#import "RenderView.h" +#import "SharedBuffer.h" +#import "StringTruncator.h" +#import "StyleResolver.h" +#import "TimeRanges.h" +#import "ThemeMac.h" +#import "WebCoreNSCellExtras.h" +#import "WebCoreSystemInterface.h" +#import "UserAgentStyleSheets.h" +#import <Carbon/Carbon.h> +#import <Cocoa/Cocoa.h> +#import <wtf/RetainPtr.h> +#import <wtf/StdLibExtras.h> +#import <math.h> + +#import "RenderProgress.h" + +#if ENABLE(METER_ELEMENT) +#include "RenderMeter.h" +#include "HTMLMeterElement.h" +#endif + +using namespace std; + +// The methods in this file are specific to the Mac OS X platform. + +// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari. + +// We estimate the animation rate of a Mac OS X progress bar is 33 fps. +// Hard code the value here because we haven't found API for it. +const double progressAnimationFrameRate = 0.033; + +// Mac OS X progress bar animation seems to have 256 frames. +const double progressAnimationNumFrames = 256; + +@interface WebCoreRenderThemeNotificationObserver : NSObject +{ + WebCore::RenderTheme *_theme; +} + +- (id)initWithTheme:(WebCore::RenderTheme *)theme; +- (void)systemColorsDidChange:(NSNotification *)notification; + +@end + +@implementation WebCoreRenderThemeNotificationObserver + +- (id)initWithTheme:(WebCore::RenderTheme *)theme +{ + if (!(self = [super init])) + return nil; + + _theme = theme; + return self; +} + +- (void)systemColorsDidChange:(NSNotification *)unusedNotification +{ + ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]); + _theme->platformColorsDidChange(); +} + +@end + +@interface NSTextFieldCell (WKDetails) +- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus; +@end + + +@interface WebCoreTextFieldCell : NSTextFieldCell +- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus; +@end + +@implementation WebCoreTextFieldCell +- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus +{ + // FIXME: This is a post-Lion-only workaround for <rdar://problem/11385461>. When that bug is resolved, we should remove this code. + CFMutableDictionaryRef coreUIDrawOptions = CFDictionaryCreateMutableCopy(NULL, 0, [super _coreUIDrawOptionsWithFrame:cellFrame inView:controlView includeFocus:includeFocus]); + CFDictionarySetValue(coreUIDrawOptions, @"borders only", kCFBooleanTrue); + return (CFDictionaryRef)[NSMakeCollectable(coreUIDrawOptions) autorelease]; +} +@end + +namespace WebCore { + +using namespace HTMLNames; + +enum { + topMargin, + rightMargin, + bottomMargin, + leftMargin +}; + +enum { + topPadding, + rightPadding, + bottomPadding, + leftPadding +}; + +RenderThemeMacShared::RenderThemeMacShared() + : m_isSliderThumbHorizontalPressed(false) + , m_isSliderThumbVerticalPressed(false) + , m_notificationObserver(AdoptNS, [[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this]) +{ + [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get() + selector:@selector(systemColorsDidChange:) + name:NSSystemColorsDidChangeNotification + object:nil]; +} + +RenderThemeMacShared::~RenderThemeMacShared() +{ + [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()]; +} + +Color RenderThemeMacShared::platformActiveSelectionBackgroundColor() const +{ + NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); +} + +Color RenderThemeMacShared::platformInactiveSelectionBackgroundColor() const +{ + NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); +} + +Color RenderThemeMacShared::platformActiveListBoxSelectionBackgroundColor() const +{ + NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); +} + +Color RenderThemeMacShared::platformActiveListBoxSelectionForegroundColor() const +{ + return Color::white; +} + +Color RenderThemeMacShared::platformInactiveListBoxSelectionForegroundColor() const +{ + return Color::black; +} + +Color RenderThemeMacShared::platformFocusRingColor() const +{ + if (usesTestModeFocusRingColor()) + return oldAquaFocusRingColor(); + + return systemColor(CSSValueWebkitFocusRingColor); +} + +Color RenderThemeMacShared::platformInactiveListBoxSelectionBackgroundColor() const +{ + return platformInactiveSelectionBackgroundColor(); +} + +static FontWeight toFontWeight(NSInteger appKitFontWeight) +{ + ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15); + if (appKitFontWeight > 14) + appKitFontWeight = 14; + else if (appKitFontWeight < 1) + appKitFontWeight = 1; + + static FontWeight fontWeights[] = { + FontWeight100, + FontWeight100, + FontWeight200, + FontWeight300, + FontWeight400, + FontWeight500, + FontWeight600, + FontWeight600, + FontWeight700, + FontWeight800, + FontWeight800, + FontWeight900, + FontWeight900, + FontWeight900 + }; + return fontWeights[appKitFontWeight - 1]; +} + +void RenderThemeMacShared::systemFont(int cssValueId, FontDescription& fontDescription) const +{ + DEFINE_STATIC_LOCAL(FontDescription, systemFont, ()); + DEFINE_STATIC_LOCAL(FontDescription, smallSystemFont, ()); + DEFINE_STATIC_LOCAL(FontDescription, menuFont, ()); + DEFINE_STATIC_LOCAL(FontDescription, labelFont, ()); + DEFINE_STATIC_LOCAL(FontDescription, miniControlFont, ()); + DEFINE_STATIC_LOCAL(FontDescription, smallControlFont, ()); + DEFINE_STATIC_LOCAL(FontDescription, controlFont, ()); + + FontDescription* cachedDesc; + NSFont* font = nil; + switch (cssValueId) { + case CSSValueSmallCaption: + cachedDesc = &smallSystemFont; + if (!smallSystemFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]; + break; + case CSSValueMenu: + cachedDesc = &menuFont; + if (!menuFont.isAbsoluteSize()) + font = [NSFont menuFontOfSize:[NSFont systemFontSize]]; + break; + case CSSValueStatusBar: + cachedDesc = &labelFont; + if (!labelFont.isAbsoluteSize()) + font = [NSFont labelFontOfSize:[NSFont labelFontSize]]; + break; + case CSSValueWebkitMiniControl: + cachedDesc = &miniControlFont; + if (!miniControlFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]]; + break; + case CSSValueWebkitSmallControl: + cachedDesc = &smallControlFont; + if (!smallControlFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]; + break; + case CSSValueWebkitControl: + cachedDesc = &controlFont; + if (!controlFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; + break; + default: + cachedDesc = &systemFont; + if (!systemFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont systemFontSize]]; + } + + if (font) { + NSFontManager *fontManager = [NSFontManager sharedFontManager]; + cachedDesc->setIsAbsoluteSize(true); + cachedDesc->setGenericFamily(FontDescription::NoFamily); + cachedDesc->firstFamily().setFamily([font familyName]); + cachedDesc->setSpecifiedSize([font pointSize]); + cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font])); + cachedDesc->setItalic([fontManager traitsOfFont:font] & NSItalicFontMask); + } + fontDescription = *cachedDesc; +} + +static RGBA32 convertNSColorToColor(NSColor *color) +{ + NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + if (colorInColorSpace) { + static const double scaleFactor = nextafter(256.0, 0.0); + return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]), + static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]), + static_cast<int>(scaleFactor * [colorInColorSpace blueComponent])); + } + + // This conversion above can fail if the NSColor in question is an NSPatternColor + // (as many system colors are). These colors are actually a repeating pattern + // not just a solid color. To work around this we simply draw a 1x1 image of + // the color and use that pixel's color. It might be better to use an average of + // the colors in the pattern instead. + NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil + pixelsWide:1 + pixelsHigh:1 + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:4 + bitsPerPixel:32]; + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]]; + NSEraseRect(NSMakeRect(0, 0, 1, 1)); + [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)]; + [NSGraphicsContext restoreGraphicsState]; + + NSUInteger pixel[4]; + [offscreenRep getPixel:pixel atX:0 y:0]; + + [offscreenRep release]; + + return makeRGB(pixel[0], pixel[1], pixel[2]); +} + +static RGBA32 menuBackgroundColor() +{ + NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil + pixelsWide:1 + pixelsHigh:1 + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:4 + bitsPerPixel:32]; + + CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]); + CGRect rect = CGRectMake(0, 0, 1, 1); + HIThemeMenuDrawInfo drawInfo; + drawInfo.version = 0; + drawInfo.menuType = kThemeMenuTypePopUp; + HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted); + + NSUInteger pixel[4]; + [offscreenRep getPixel:pixel atX:0 y:0]; + + [offscreenRep release]; + + return makeRGB(pixel[0], pixel[1], pixel[2]); +} + +void RenderThemeMacShared::platformColorsDidChange() +{ + m_systemColorCache.clear(); + RenderTheme::platformColorsDidChange(); +} + +Color RenderThemeMacShared::systemColor(int cssValueId) const +{ + { + HashMap<int, RGBA32>::iterator it = m_systemColorCache.find(cssValueId); + if (it != m_systemColorCache.end()) + return it->value; + } + + Color color; + switch (cssValueId) { + case CSSValueActiveborder: + color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); + break; + case CSSValueActivecaption: + color = convertNSColorToColor([NSColor windowFrameTextColor]); + break; + case CSSValueAppworkspace: + color = convertNSColorToColor([NSColor headerColor]); + break; + case CSSValueBackground: + // Use theme independent default + break; + case CSSValueButtonface: + // We use this value instead of NSColor's controlColor to avoid website incompatibilities. + // We may want to change this to use the NSColor in future. + color = 0xFFC0C0C0; + break; + case CSSValueButtonhighlight: + color = convertNSColorToColor([NSColor controlHighlightColor]); + break; + case CSSValueButtonshadow: + color = convertNSColorToColor([NSColor controlShadowColor]); + break; + case CSSValueButtontext: + color = convertNSColorToColor([NSColor controlTextColor]); + break; + case CSSValueCaptiontext: + color = convertNSColorToColor([NSColor textColor]); + break; + case CSSValueGraytext: + color = convertNSColorToColor([NSColor disabledControlTextColor]); + break; + case CSSValueHighlight: + color = convertNSColorToColor([NSColor selectedTextBackgroundColor]); + break; + case CSSValueHighlighttext: + color = convertNSColorToColor([NSColor selectedTextColor]); + break; + case CSSValueInactiveborder: + color = convertNSColorToColor([NSColor controlBackgroundColor]); + break; + case CSSValueInactivecaption: + color = convertNSColorToColor([NSColor controlBackgroundColor]); + break; + case CSSValueInactivecaptiontext: + color = convertNSColorToColor([NSColor textColor]); + break; + case CSSValueInfobackground: + // There is no corresponding NSColor for this so we use a hard coded value. + color = 0xFFFBFCC5; + break; + case CSSValueInfotext: + color = convertNSColorToColor([NSColor textColor]); + break; + case CSSValueMenu: + color = menuBackgroundColor(); + break; + case CSSValueMenutext: + color = convertNSColorToColor([NSColor selectedMenuItemTextColor]); + break; + case CSSValueScrollbar: + color = convertNSColorToColor([NSColor scrollBarColor]); + break; + case CSSValueText: + color = convertNSColorToColor([NSColor textColor]); + break; + case CSSValueThreeddarkshadow: + color = convertNSColorToColor([NSColor controlDarkShadowColor]); + break; + case CSSValueThreedshadow: + color = convertNSColorToColor([NSColor shadowColor]); + break; + case CSSValueThreedface: + // We use this value instead of NSColor's controlColor to avoid website incompatibilities. + // We may want to change this to use the NSColor in future. + color = 0xFFC0C0C0; + break; + case CSSValueThreedhighlight: + color = convertNSColorToColor([NSColor highlightColor]); + break; + case CSSValueThreedlightshadow: + color = convertNSColorToColor([NSColor controlLightHighlightColor]); + break; + case CSSValueWebkitFocusRingColor: + color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); + break; + case CSSValueWindow: + color = convertNSColorToColor([NSColor windowBackgroundColor]); + break; + case CSSValueWindowframe: + color = convertNSColorToColor([NSColor windowFrameColor]); + break; + case CSSValueWindowtext: + color = convertNSColorToColor([NSColor windowFrameTextColor]); + break; + } + + if (!color.isValid()) + color = RenderTheme::systemColor(cssValueId); + + if (color.isValid()) + m_systemColorCache.set(cssValueId, color.rgb()); + + return color; +} + +bool RenderThemeMacShared::usesTestModeFocusRingColor() const +{ + return WebCore::usesTestModeFocusRingColor(); +} + +bool RenderThemeMacShared::isControlStyled(const RenderStyle* style, const BorderData& border, + const FillLayer& background, const Color& backgroundColor) const +{ + if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart) + return style->border() != border; + + // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when + // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style + // adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming + // is in effect we treat it like the control is styled. + if (style->appearance() == MenulistPart && style->effectiveZoom() != 1.0f) + return true; + + return RenderTheme::isControlStyled(style, border, background, backgroundColor); +} + +void RenderThemeMacShared::adjustRepaintRect(const RenderObject* o, IntRect& r) +{ + ControlPart part = o->style()->appearance(); + +#if USE(NEW_THEME) + switch (part) { + case CheckboxPart: + case RadioPart: + case PushButtonPart: + case SquareButtonPart: + case DefaultButtonPart: + case ButtonPart: + case InnerSpinButtonPart: + return RenderTheme::adjustRepaintRect(o, r); + default: + break; + } +#endif + + float zoomLevel = o->style()->effectiveZoom(); + + if (part == MenulistPart) { + setPopupButtonCellState(o, r); + IntSize size = popupButtonSizes()[[popupButton() controlSize]]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(r.width()); + r = inflateRect(r, size, popupButtonMargins(), zoomLevel); + } +} + +IntRect RenderThemeMacShared::inflateRect(const IntRect& r, const IntSize& size, const int* margins, float zoomLevel) const +{ + // Only do the inflation if the available width/height are too small. Otherwise try to + // fit the glow/check space into the available box's width/height. + int widthDelta = r.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel); + int heightDelta = r.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel); + IntRect result(r); + if (widthDelta < 0) { + result.setX(result.x() - margins[leftMargin] * zoomLevel); + result.setWidth(result.width() - widthDelta); + } + if (heightDelta < 0) { + result.setY(result.y() - margins[topMargin] * zoomLevel); + result.setHeight(result.height() - heightDelta); + } + return result; +} + +FloatRect RenderThemeMacShared::convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const +{ + FloatRect partRect(inputRect); + + // Compute an offset between the part renderer and the input renderer + FloatSize offsetFromInputRenderer; + const RenderObject* renderer = partRenderer; + while (renderer && renderer != inputRenderer) { + RenderObject* containingRenderer = renderer->container(); + offsetFromInputRenderer -= roundedIntSize(renderer->offsetFromContainer(containingRenderer, LayoutPoint())); + renderer = containingRenderer; + } + // If the input renderer was not a container, something went wrong + ASSERT(renderer == inputRenderer); + // Move the rect into partRenderer's coords + partRect.move(offsetFromInputRenderer); + // Account for the local drawing offset (tx, ty) + partRect.move(r.x(), r.y()); + + return partRect; +} + +void RenderThemeMacShared::updateCheckedState(NSCell* cell, const RenderObject* o) +{ + bool oldIndeterminate = [cell state] == NSMixedState; + bool indeterminate = isIndeterminate(o); + bool checked = isChecked(o); + + if (oldIndeterminate != indeterminate) { + [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)]; + return; + } + + bool oldChecked = [cell state] == NSOnState; + if (checked != oldChecked) + [cell setState:checked ? NSOnState : NSOffState]; +} + +void RenderThemeMacShared::updateEnabledState(NSCell* cell, const RenderObject* o) +{ + bool oldEnabled = [cell isEnabled]; + bool enabled = isEnabled(o); + if (enabled != oldEnabled) + [cell setEnabled:enabled]; +} + +void RenderThemeMacShared::updateFocusedState(NSCell* cell, const RenderObject* o) +{ + bool oldFocused = [cell showsFirstResponder]; + bool focused = isFocused(o) && o->style()->outlineStyleIsAuto(); + if (focused != oldFocused) + [cell setShowsFirstResponder:focused]; +} + +void RenderThemeMacShared::updatePressedState(NSCell* cell, const RenderObject* o) +{ + bool oldPressed = [cell isHighlighted]; + bool pressed = (o->node() && o->node()->active()); + if (pressed != oldPressed) + [cell setHighlighted:pressed]; +} + +bool RenderThemeMacShared::controlSupportsTints(const RenderObject* o) const +{ + // An alternate way to implement this would be to get the appropriate cell object + // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of + // that would be that we would match AppKit behavior more closely, but a disadvantage + // would be that we would rely on an AppKit SPI method. + + if (!isEnabled(o)) + return false; + + // Checkboxes only have tint when checked. + if (o->style()->appearance() == CheckboxPart) + return isChecked(o); + + // For now assume other controls have tint if enabled. + return true; +} + +NSControlSize RenderThemeMacShared::controlSizeForFont(RenderStyle* style) const +{ + int fontSize = style->fontSize(); + if (fontSize >= 16) + return NSRegularControlSize; + if (fontSize >= 11) + return NSSmallControlSize; + return NSMiniControlSize; +} + +void RenderThemeMacShared::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel) +{ + NSControlSize size; + if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel) && + minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel)) + size = NSRegularControlSize; + else if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel) && + minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel)) + size = NSSmallControlSize; + else + size = NSMiniControlSize; + if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same. + [cell setControlSize:size]; +} + +IntSize RenderThemeMacShared::sizeForFont(RenderStyle* style, const IntSize* sizes) const +{ + if (style->effectiveZoom() != 1.0f) { + IntSize result = sizes[controlSizeForFont(style)]; + return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom()); + } + return sizes[controlSizeForFont(style)]; +} + +IntSize RenderThemeMacShared::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const +{ + if (style->effectiveZoom() != 1.0f) { + IntSize result = sizes[controlSizeForSystemFont(style)]; + return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom()); + } + return sizes[controlSizeForSystemFont(style)]; +} + +void RenderThemeMacShared::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const +{ + // FIXME: Check is flawed, since it doesn't take min-width/max-width into account. + IntSize size = sizeForFont(style, sizes); + if (style->width().isIntrinsicOrAuto() && size.width() > 0) + style->setWidth(Length(size.width(), Fixed)); + if (style->height().isAuto() && size.height() > 0) + style->setHeight(Length(size.height(), Fixed)); +} + +void RenderThemeMacShared::setFontFromControlSize(StyleResolver*, RenderStyle* style, NSControlSize controlSize) const +{ + FontDescription fontDescription; + fontDescription.setIsAbsoluteSize(true); + fontDescription.setGenericFamily(FontDescription::SerifFamily); + + NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]]; + fontDescription.firstFamily().setFamily([font familyName]); + fontDescription.setComputedSize([font pointSize] * style->effectiveZoom()); + fontDescription.setSpecifiedSize([font pointSize] * style->effectiveZoom()); + + // Reset line height + style->setLineHeight(RenderStyle::initialLineHeight()); + + if (style->setFontDescription(fontDescription)) + style->font().update(0); +} + +NSControlSize RenderThemeMacShared::controlSizeForSystemFont(RenderStyle* style) const +{ + int fontSize = style->fontSize(); + if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize]) + return NSRegularControlSize; + if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize]) + return NSSmallControlSize; + return NSMiniControlSize; +} + +bool RenderThemeMacShared::paintTextField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + +#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 + bool useNSTextFieldCell = o->style()->hasAppearance() + && o->style()->visitedDependentColor(CSSPropertyBackgroundColor) == Color::white + && !o->style()->hasBackgroundImage(); + + // We do not use NSTextFieldCell to draw styled text fields on Lion and SnowLeopard because + // there are a number of bugs on those platforms that require NSTextFieldCell to be in charge + // of painting its own background. We need WebCore to paint styled backgrounds, so we'll use + // this WebCoreSystemInterface function instead. + if (!useNSTextFieldCell) { + wkDrawBezeledTextFieldCell(r, isEnabled(o) && !isReadOnlyControl(o)); + return false; + } +#endif + + NSTextFieldCell *textField = this->textField(); + + GraphicsContextStateSaver stateSaver(*paintInfo.context); + + [textField setEnabled:(isEnabled(o) && !isReadOnlyControl(o))]; + [textField drawWithFrame:NSRect(r) inView:documentViewFor(o)]; + + [textField setControlView:nil]; + + return false; +} + +void RenderThemeMacShared::adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const +{ +} + +bool RenderThemeMacShared::paintCapsLockIndicator(RenderObject*, const PaintInfo& paintInfo, const IntRect& r) +{ + if (paintInfo.context->paintingDisabled()) + return true; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawCapsLockIndicator(localContext.cgContext(), r); + + return false; +} + +bool RenderThemeMacShared::paintTextArea(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawBezeledTextArea(r, isEnabled(o) && !isReadOnlyControl(o)); + return false; +} + +void RenderThemeMacShared::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const +{ +} + +const int* RenderThemeMacShared::popupButtonMargins() const +{ + static const int margins[3][4] = + { + { 0, 3, 1, 3 }, + { 0, 3, 2, 3 }, + { 0, 1, 0, 1 } + }; + return margins[[popupButton() controlSize]]; +} + +const IntSize* RenderThemeMacShared::popupButtonSizes() const +{ + static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; + return sizes; +} + +const int* RenderThemeMacShared::popupButtonPadding(NSControlSize size) const +{ + static const int padding[3][4] = + { + { 2, 26, 3, 8 }, + { 2, 23, 3, 8 }, + { 2, 22, 3, 10 } + }; + return padding[size]; +} + +bool RenderThemeMacShared::paintMenuList(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + setPopupButtonCellState(o, r); + + NSPopUpButtonCell* popupButton = this->popupButton(); + + float zoomLevel = o->style()->effectiveZoom(); + IntSize size = popupButtonSizes()[[popupButton controlSize]]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(r.width()); + + // Now inflate it to account for the shadow. + IntRect inflatedRect = r; + if (r.width() >= minimumMenuListSize(o->style())) + inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel); + + GraphicsContextStateSaver stateSaver(*paintInfo.context); + + // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect + paintInfo.context->clip(inflatedRect); + + if (zoomLevel != 1.0f) { + inflatedRect.setWidth(inflatedRect.width() / zoomLevel); + inflatedRect.setHeight(inflatedRect.height() / zoomLevel); + paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); + } + + NSView *view = documentViewFor(o); + [popupButton drawWithFrame:inflatedRect inView:view]; +#if !BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING + if (isFocused(o) && o->style()->outlineStyleIsAuto()) + [popupButton _web_drawFocusRingWithFrame:inflatedRect inView:view]; +#endif + [popupButton setControlView:nil]; + + return false; +} + +#if ENABLE(METER_ELEMENT) + +IntSize RenderThemeMacShared::meterSizeForBounds(const RenderMeter* renderMeter, const IntRect& bounds) const +{ + if (NoControlPart == renderMeter->style()->appearance()) + return bounds.size(); + + NSLevelIndicatorCell* cell = levelIndicatorFor(renderMeter); + // Makes enough room for cell's intrinsic size. + NSSize cellSize = [cell cellSizeForBounds:IntRect(IntPoint(), bounds.size())]; + return IntSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(), + bounds.height() < cellSize.height ? cellSize.height : bounds.height()); +} + +bool RenderThemeMacShared::paintMeter(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) +{ + if (!renderObject->isMeter()) + return true; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + + NSLevelIndicatorCell* cell = levelIndicatorFor(toRenderMeter(renderObject)); + GraphicsContextStateSaver stateSaver(*paintInfo.context); + + [cell drawWithFrame:rect inView:documentViewFor(renderObject)]; + [cell setControlView:nil]; + return false; +} + +bool RenderThemeMacShared::supportsMeter(ControlPart part) const +{ + switch (part) { + case RelevancyLevelIndicatorPart: + case DiscreteCapacityLevelIndicatorPart: + case RatingLevelIndicatorPart: + case MeterPart: + case ContinuousCapacityLevelIndicatorPart: + return true; + default: + return false; + } +} + +NSLevelIndicatorStyle RenderThemeMacShared::levelIndicatorStyleFor(ControlPart part) const +{ + switch (part) { + case RelevancyLevelIndicatorPart: + return NSRelevancyLevelIndicatorStyle; + case DiscreteCapacityLevelIndicatorPart: + return NSDiscreteCapacityLevelIndicatorStyle; + case RatingLevelIndicatorPart: + return NSRatingLevelIndicatorStyle; + case MeterPart: + case ContinuousCapacityLevelIndicatorPart: + default: + return NSContinuousCapacityLevelIndicatorStyle; + } + +} + +NSLevelIndicatorCell* RenderThemeMacShared::levelIndicatorFor(const RenderMeter* renderMeter) const +{ + RenderStyle* style = renderMeter->style(); + ASSERT(style->appearance() != NoControlPart); + + if (!m_levelIndicator) + m_levelIndicator.adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]); + NSLevelIndicatorCell* cell = m_levelIndicator.get(); + + HTMLMeterElement* element = renderMeter->meterElement(); + double value = element->value(); + + // Because NSLevelIndicatorCell does not support optimum-in-the-middle type coloring, + // we explicitly control the color instead giving low and high value to NSLevelIndicatorCell as is. + switch (element->gaugeRegion()) { + case HTMLMeterElement::GaugeRegionOptimum: + // Make meter the green + [cell setWarningValue:value + 1]; + [cell setCriticalValue:value + 2]; + break; + case HTMLMeterElement::GaugeRegionSuboptimal: + // Make the meter yellow + [cell setWarningValue:value - 1]; + [cell setCriticalValue:value + 1]; + break; + case HTMLMeterElement::GaugeRegionEvenLessGood: + // Make the meter red + [cell setWarningValue:value - 2]; + [cell setCriticalValue:value - 1]; + break; + } + + [cell setLevelIndicatorStyle:levelIndicatorStyleFor(style->appearance())]; + [cell setBaseWritingDirection:style->isLeftToRightDirection() ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft]; + [cell setMinValue:element->min()]; + [cell setMaxValue:element->max()]; + RetainPtr<NSNumber> valueObject = [NSNumber numberWithDouble:value]; + [cell setObjectValue:valueObject.get()]; + + return cell; +} + +#endif + +#if ENABLE(PROGRESS_ELEMENT) +const IntSize* RenderThemeMacShared::progressBarSizes() const +{ + static const IntSize sizes[3] = { IntSize(0, 20), IntSize(0, 12), IntSize(0, 12) }; + return sizes; +} + +const int* RenderThemeMacShared::progressBarMargins(NSControlSize controlSize) const +{ + static const int margins[3][4] = + { + { 0, 0, 1, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 1, 0 }, + }; + return margins[controlSize]; +} + +int RenderThemeMacShared::minimumProgressBarHeight(RenderStyle* style) const +{ + return sizeForSystemFont(style, progressBarSizes()).height(); +} + +double RenderThemeMacShared::animationRepeatIntervalForProgressBar(RenderProgress*) const +{ + return progressAnimationFrameRate; +} + +double RenderThemeMacShared::animationDurationForProgressBar(RenderProgress*) const +{ + return progressAnimationNumFrames * progressAnimationFrameRate; +} + +void RenderThemeMacShared::adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const +{ +} + +bool RenderThemeMacShared::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) +{ + if (!renderObject->isProgress()) + return true; + + float zoomLevel = renderObject->style()->effectiveZoom(); + int controlSize = controlSizeForFont(renderObject->style()); + IntSize size = progressBarSizes()[controlSize]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(rect.width()); + + // Now inflate it to account for the shadow. + IntRect inflatedRect = rect; + if (rect.height() <= minimumProgressBarHeight(renderObject->style())) + inflatedRect = inflateRect(inflatedRect, size, progressBarMargins(controlSize), zoomLevel); + + RenderProgress* renderProgress = toRenderProgress(renderObject); + HIThemeTrackDrawInfo trackInfo; + trackInfo.version = 0; + if (controlSize == NSRegularControlSize) + trackInfo.kind = renderProgress->position() < 0 ? kThemeLargeIndeterminateBar : kThemeLargeProgressBar; + else + trackInfo.kind = renderProgress->position() < 0 ? kThemeMediumIndeterminateBar : kThemeMediumProgressBar; + + trackInfo.bounds = IntRect(IntPoint(), inflatedRect.size()); + trackInfo.min = 0; + trackInfo.max = numeric_limits<SInt32>::max(); + trackInfo.value = lround(renderProgress->position() * nextafter(trackInfo.max, 0)); + trackInfo.trackInfo.progress.phase = lround(renderProgress->animationProgress() * nextafter(progressAnimationNumFrames, 0)); + trackInfo.attributes = kThemeTrackHorizontal; + trackInfo.enableState = isActive(renderObject) ? kThemeTrackActive : kThemeTrackInactive; + trackInfo.reserved = 0; + trackInfo.filler1 = 0; + + OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(inflatedRect.size(), 1); + if (!imageBuffer) + return true; + + ContextContainer cgContextContainer(imageBuffer->context()); + CGContextRef cgContext = cgContextContainer.context(); + HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal); + + GraphicsContextStateSaver stateSaver(*paintInfo.context); + + if (!renderProgress->style()->isLeftToRightDirection()) { + paintInfo.context->translate(2 * inflatedRect.x() + inflatedRect.width(), 0); + paintInfo.context->scale(FloatSize(-1, 1)); + } + + paintInfo.context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, inflatedRect.location()); + return false; +} +#endif + +const float baseFontSize = 11.0f; +const float baseArrowHeight = 4.0f; +const float baseArrowWidth = 5.0f; +const float baseSpaceBetweenArrows = 2.0f; +const int arrowPaddingLeft = 6; +const int arrowPaddingRight = 6; +const int paddingBeforeSeparator = 4; +const int baseBorderRadius = 5; +const int styledPopupPaddingLeft = 8; +const int styledPopupPaddingTop = 1; +const int styledPopupPaddingBottom = 2; + +static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) +{ + static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f }; + static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f }; + float a = inData[0]; + int i = 0; + for (i = 0; i < 4; i++) + outData[i] = (1.0f - a) * dark[i] + a * light[i]; +} + +static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) +{ + static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f }; + static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f }; + float a = inData[0]; + int i = 0; + for (i = 0; i < 4; i++) + outData[i] = (1.0f - a) * dark[i] + a * light[i]; +} + +static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) +{ + static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f }; + static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + float a = inData[0]; + int i = 0; + for (i = 0; i < 4; i++) + outData[i] = (1.0f - a) * dark[i] + a * light[i]; +} + +static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) +{ + static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f }; + static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f }; + float a = inData[0]; + int i = 0; + for (i = 0; i < 4; i++) + outData[i] = (1.0f - a) * dark[i] + a * light[i]; +} + +void RenderThemeMacShared::paintMenuListButtonGradients(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + if (r.isEmpty()) + return; + + ContextContainer cgContextContainer(paintInfo.context); + CGContextRef context = cgContextContainer.context(); + + GraphicsContextStateSaver stateSaver(*paintInfo.context); + + RoundedRect border = o->style()->getRoundedBorderFor(r, o->view()); + int radius = border.radii().topLeft().width(); + + CGColorSpaceRef cspace = deviceRGBColorSpaceRef(); + + FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f); + struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL }; + RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks)); + RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false)); + + FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f); + struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL }; + RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks)); + RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false)); + + struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL }; + RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); + RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false)); + + RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false)); + + RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false)); + + { + GraphicsContextStateSaver stateSaver(*paintInfo.context); + CGContextClipToRect(context, r); + paintInfo.context->addRoundedRectClip(border); + context = cgContextContainer.context(); + CGContextDrawShading(context, mainShading.get()); + } + + { + GraphicsContextStateSaver stateSaver(*paintInfo.context); + CGContextClipToRect(context, topGradient); + paintInfo.context->addRoundedRectClip(RoundedRect(enclosingIntRect(topGradient), border.radii().topLeft(), border.radii().topRight(), IntSize(), IntSize())); + context = cgContextContainer.context(); + CGContextDrawShading(context, topShading.get()); + } + + if (!bottomGradient.isEmpty()) { + GraphicsContextStateSaver stateSaver(*paintInfo.context); + CGContextClipToRect(context, bottomGradient); + paintInfo.context->addRoundedRectClip(RoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), border.radii().bottomLeft(), border.radii().bottomRight())); + context = cgContextContainer.context(); + CGContextDrawShading(context, bottomShading.get()); + } + + { + GraphicsContextStateSaver stateSaver(*paintInfo.context); + CGContextClipToRect(context, r); + paintInfo.context->addRoundedRectClip(border); + context = cgContextContainer.context(); + CGContextDrawShading(context, leftShading.get()); + CGContextDrawShading(context, rightShading.get()); + } +} + +bool RenderThemeMacShared::paintMenuListButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(), + r.y() + o->style()->borderTopWidth(), + r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(), + r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth()); + // Draw the gradients to give the styled popup menu a button appearance + paintMenuListButtonGradients(o, paintInfo, bounds); + + // Since we actually know the size of the control here, we restrict the font scale to make sure the arrows will fit vertically in the bounds + float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows)); + float centerY = bounds.y() + bounds.height() / 2.0f; + float arrowHeight = baseArrowHeight * fontScale; + float arrowWidth = baseArrowWidth * fontScale; + float leftEdge = bounds.maxX() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth; + float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale; + + if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom()) + return false; + + GraphicsContextStateSaver stateSaver(*paintInfo.context); + + paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), o->style()->colorSpace()); + paintInfo.context->setStrokeStyle(NoStroke); + + FloatPoint arrow1[3]; + arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f); + arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f); + arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight); + + // Draw the top arrow + paintInfo.context->drawConvexPolygon(3, arrow1, true); + + FloatPoint arrow2[3]; + arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f); + arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f); + arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight); + + // Draw the bottom arrow + paintInfo.context->drawConvexPolygon(3, arrow2, true); + + Color leftSeparatorColor(0, 0, 0, 40); + Color rightSeparatorColor(255, 255, 255, 40); + + // FIXME: Should the separator thickness and space be scaled up by fontScale? + int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin. + int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * o->style()->effectiveZoom()); // FIXME: Round? + + // Draw the separator to the left of the arrows + paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin. + paintInfo.context->setStrokeStyle(SolidStroke); + paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB); + paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()), + IntPoint(leftEdgeOfSeparator, bounds.maxY())); + + paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB); + paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()), + IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY())); + return false; +} + +static const IntSize* menuListButtonSizes() +{ + static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; + return sizes; +} + +void RenderThemeMacShared::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const +{ + NSControlSize controlSize = controlSizeForFont(style); + + style->resetBorder(); + style->resetPadding(); + + // Height is locked to auto. + style->setHeight(Length(Auto)); + + // White-space is locked to pre + style->setWhiteSpace(PRE); + + // Set the foreground color to black or gray when we have the aqua look. + // Cast to RGB32 is to work around a compiler bug. + style->setColor(e && e->isEnabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray); + + // Set the button's vertical size. + setSizeFromFont(style, menuListButtonSizes()); + + // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out + // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate + // system font for the control size instead. + setFontFromControlSize(styleResolver, style, controlSize); + + style->setBoxShadow(nullptr); +} + +int RenderThemeMacShared::popupInternalPaddingLeft(RenderStyle* style) const +{ + if (style->appearance() == MenulistPart) + return popupButtonPadding(controlSizeForFont(style))[leftPadding] * style->effectiveZoom(); + if (style->appearance() == MenulistButtonPart) + return styledPopupPaddingLeft * style->effectiveZoom(); + return 0; +} + +int RenderThemeMacShared::popupInternalPaddingRight(RenderStyle* style) const +{ + if (style->appearance() == MenulistPart) + return popupButtonPadding(controlSizeForFont(style))[rightPadding] * style->effectiveZoom(); + if (style->appearance() == MenulistButtonPart) { + float fontScale = style->fontSize() / baseFontSize; + float arrowWidth = baseArrowWidth * fontScale; + return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom())); + } + return 0; +} + +int RenderThemeMacShared::popupInternalPaddingTop(RenderStyle* style) const +{ + if (style->appearance() == MenulistPart) + return popupButtonPadding(controlSizeForFont(style))[topPadding] * style->effectiveZoom(); + if (style->appearance() == MenulistButtonPart) + return styledPopupPaddingTop * style->effectiveZoom(); + return 0; +} + +int RenderThemeMacShared::popupInternalPaddingBottom(RenderStyle* style) const +{ + if (style->appearance() == MenulistPart) + return popupButtonPadding(controlSizeForFont(style))[bottomPadding] * style->effectiveZoom(); + if (style->appearance() == MenulistButtonPart) + return styledPopupPaddingBottom * style->effectiveZoom(); + return 0; +} + +void RenderThemeMacShared::adjustMenuListButtonStyle(StyleResolver*, RenderStyle* style, Element*) const +{ + float fontScale = style->fontSize() / baseFontSize; + + style->resetPadding(); + style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up? + + const int minHeight = 15; + style->setMinHeight(Length(minHeight, Fixed)); + + style->setLineHeight(RenderStyle::initialLineHeight()); +} + +void RenderThemeMacShared::setPopupButtonCellState(const RenderObject* o, const IntRect& r) +{ + NSPopUpButtonCell* popupButton = this->popupButton(); + + // Set the control size based off the rectangle we're painting into. + setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom()); + + // Update the various states we respond to. + updateActiveState(popupButton, o); + updateCheckedState(popupButton, o); + updateEnabledState(popupButton, o); + updatePressedState(popupButton, o); +#if BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING + updateFocusedState(popupButton, o); +#endif +} + +const IntSize* RenderThemeMacShared::menuListSizes() const +{ + static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) }; + return sizes; +} + +int RenderThemeMacShared::minimumMenuListSize(RenderStyle* style) const +{ + return sizeForSystemFont(style, menuListSizes()).width(); +} + +const int trackWidth = 5; +const int trackRadius = 2; + +void RenderThemeMacShared::adjustSliderTrackStyle(StyleResolver*, RenderStyle* style, Element*) const +{ + style->setBoxShadow(nullptr); +} + +bool RenderThemeMacShared::paintSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + IntRect bounds = r; + float zoomLevel = o->style()->effectiveZoom(); + float zoomedTrackWidth = trackWidth * zoomLevel; + + if (o->style()->appearance() == SliderHorizontalPart || o->style()->appearance() == MediaSliderPart) { + bounds.setHeight(zoomedTrackWidth); + bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2); + } else if (o->style()->appearance() == SliderVerticalPart) { + bounds.setWidth(zoomedTrackWidth); + bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2); + } + + LocalCurrentGraphicsContext localContext(paintInfo.context); + CGContextRef context = localContext.cgContext(); + CGColorSpaceRef cspace = deviceRGBColorSpaceRef(); + +#if ENABLE(DATALIST_ELEMENT) + paintSliderTicks(o, paintInfo, r); +#endif + + GraphicsContextStateSaver stateSaver(*paintInfo.context); + CGContextClipToRect(context, bounds); + + struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL }; + RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); + RetainPtr<CGShadingRef> mainShading; + if (o->style()->appearance() == SliderVerticalPart) + mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.maxY()), CGPointMake(bounds.maxX(), bounds.maxY()), mainFunction.get(), false, false)); + else + mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.maxY()), mainFunction.get(), false, false)); + + IntSize radius(trackRadius, trackRadius); + paintInfo.context->addRoundedRectClip(RoundedRect(bounds, radius, radius, radius, radius)); + context = localContext.cgContext(); + CGContextDrawShading(context, mainShading.get()); + + return false; +} + +void RenderThemeMacShared::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const +{ + RenderTheme::adjustSliderThumbStyle(styleResolver, style, element); + style->setBoxShadow(nullptr); +} + +const float verticalSliderHeightPadding = 0.1f; + +bool RenderThemeMacShared::paintSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + NSSliderCell* sliderThumbCell = o->style()->appearance() == SliderThumbVerticalPart + ? sliderThumbVertical() + : sliderThumbHorizontal(); + + LocalCurrentGraphicsContext localContext(paintInfo.context); + + // Update the various states we respond to. + updateActiveState(sliderThumbCell, o); + updateEnabledState(sliderThumbCell, o); + updateFocusedState(sliderThumbCell, (o->node() && o->node()->focusDelegate()->renderer()) ? o->node()->focusDelegate()->renderer() : o); + + // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it. + bool oldPressed; + if (o->style()->appearance() == SliderThumbVerticalPart) + oldPressed = m_isSliderThumbVerticalPressed; + else + oldPressed = m_isSliderThumbHorizontalPressed; + + bool pressed = isPressed(o); + + if (o->style()->appearance() == SliderThumbVerticalPart) + m_isSliderThumbVerticalPressed = pressed; + else + m_isSliderThumbHorizontalPressed = pressed; + + if (pressed != oldPressed) { + if (pressed) + [sliderThumbCell startTrackingAt:NSPoint() inView:nil]; + else + [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES]; + } + + FloatRect bounds = r; + // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider. + if (o->style()->appearance() == SliderThumbVerticalPart) + bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o->style()->effectiveZoom()); + + GraphicsContextStateSaver stateSaver(*paintInfo.context); + float zoomLevel = o->style()->effectiveZoom(); + + FloatRect unzoomedRect = bounds; + if (zoomLevel != 1.0f) { + unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); + unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); + paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); + } + +#if PLATFORM(CHROMIUM) + paintInfo.context->translate(0, unzoomedRect.y()); + paintInfo.context->scale(FloatSize(1, -1)); + paintInfo.context->translate(0, -(unzoomedRect.y() + unzoomedRect.height())); +#endif + + [sliderThumbCell drawInteriorWithFrame:unzoomedRect inView:documentViewFor(o)]; + [sliderThumbCell setControlView:nil]; + + return false; +} + +bool RenderThemeMacShared::paintSearchField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + NSSearchFieldCell* search = this->search(); + + setSearchCellState(o, r); + + GraphicsContextStateSaver stateSaver(*paintInfo.context); + + float zoomLevel = o->style()->effectiveZoom(); + + IntRect unzoomedRect = r; + + if (zoomLevel != 1.0f) { + unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); + unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); + paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); + } + + // Set the search button to nil before drawing. Then reset it so we can draw it later. + [search setSearchButtonCell:nil]; + + [search drawWithFrame:NSRect(unzoomedRect) inView:documentViewFor(o)]; + + [search setControlView:nil]; + [search resetSearchButtonCell]; + + return false; +} + +void RenderThemeMacShared::setSearchCellState(RenderObject* o, const IntRect&) +{ + NSSearchFieldCell* search = this->search(); + + [search setControlSize:controlSizeForFont(o->style())]; + + // Update the various states we respond to. + updateActiveState(search, o); + updateEnabledState(search, o); + updateFocusedState(search, o); +} + +const IntSize* RenderThemeMacShared::searchFieldSizes() const +{ + static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) }; + return sizes; +} + +void RenderThemeMacShared::setSearchFieldSize(RenderStyle* style) const +{ + // If the width and height are both specified, then we have nothing to do. + if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) + return; + + // Use the font size to determine the intrinsic width of the control. + setSizeFromFont(style, searchFieldSizes()); +} + +void RenderThemeMacShared::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element*) const +{ + // Override border. + style->resetBorder(); + const short borderWidth = 2 * style->effectiveZoom(); + style->setBorderLeftWidth(borderWidth); + style->setBorderLeftStyle(INSET); + style->setBorderRightWidth(borderWidth); + style->setBorderRightStyle(INSET); + style->setBorderBottomWidth(borderWidth); + style->setBorderBottomStyle(INSET); + style->setBorderTopWidth(borderWidth); + style->setBorderTopStyle(INSET); + + // Override height. + style->setHeight(Length(Auto)); + setSearchFieldSize(style); + + // Override padding size to match AppKit text positioning. + const int padding = 1 * style->effectiveZoom(); + style->setPaddingLeft(Length(padding, Fixed)); + style->setPaddingRight(Length(padding, Fixed)); + style->setPaddingTop(Length(padding, Fixed)); + style->setPaddingBottom(Length(padding, Fixed)); + + NSControlSize controlSize = controlSizeForFont(style); + setFontFromControlSize(styleResolver, style, controlSize); + + style->setBoxShadow(nullptr); +} + +bool RenderThemeMacShared::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + Element* input = o->node()->shadowHost(); + if (!input) + input = toElement(o->node()); + + if (!input->renderer()->isBox()) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + setSearchCellState(input->renderer(), r); + + NSSearchFieldCell* search = this->search(); + + if (input->isEnabledFormControl() && (input->isTextFormControl() && !static_cast<HTMLTextFormControlElement*>(input)->readOnly())) { + updateActiveState([search cancelButtonCell], o); + updatePressedState([search cancelButtonCell], o); + } + else if ([[search cancelButtonCell] isHighlighted]) + [[search cancelButtonCell] setHighlighted:NO]; + + GraphicsContextStateSaver stateSaver(*paintInfo.context); + + float zoomLevel = o->style()->effectiveZoom(); + + FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())]; + +#if ENABLE(INPUT_SPEECH) + // Take care of cases where the cancel button was not aligned with the right border of the input element (for e.g. + // when speech input is enabled for the input element. + IntRect absBoundingBox = input->renderer()->absoluteBoundingBoxRect(); + int absRight = absBoundingBox.x() + absBoundingBox.width() - input->renderBox()->paddingRight() - input->renderBox()->borderRight(); + int spaceToRightOfCancelButton = absRight - (r.x() + r.width()); + localBounds.setX(localBounds.x() - spaceToRightOfCancelButton); +#endif + + localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); + + FloatRect unzoomedRect(localBounds); + if (zoomLevel != 1.0f) { + unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); + unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); + paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); + } + + [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)]; + [[search cancelButtonCell] setControlView:nil]; + return false; +} + +const IntSize* RenderThemeMacShared::cancelButtonSizes() const +{ + static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) }; + return sizes; +} + +void RenderThemeMacShared::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const +{ + IntSize size = sizeForSystemFont(style, cancelButtonSizes()); + style->setWidth(Length(size.width(), Fixed)); + style->setHeight(Length(size.height(), Fixed)); + style->setBoxShadow(nullptr); +} + +const IntSize* RenderThemeMacShared::resultsButtonSizes() const +{ + static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) }; + return sizes; +} + +const int emptyResultsOffset = 9; +void RenderThemeMacShared::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const +{ + IntSize size = sizeForSystemFont(style, resultsButtonSizes()); + style->setWidth(Length(size.width() - emptyResultsOffset, Fixed)); + style->setHeight(Length(size.height(), Fixed)); + style->setBoxShadow(nullptr); +} + +bool RenderThemeMacShared::paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&) +{ + return false; +} + +void RenderThemeMacShared::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const +{ + IntSize size = sizeForSystemFont(style, resultsButtonSizes()); + style->setWidth(Length(size.width(), Fixed)); + style->setHeight(Length(size.height(), Fixed)); + style->setBoxShadow(nullptr); +} + +bool RenderThemeMacShared::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + Node* input = o->node()->shadowHost(); + if (!input) + input = o->node(); + if (!input->renderer()->isBox()) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + setSearchCellState(input->renderer(), r); + + NSSearchFieldCell* search = this->search(); + + if ([search searchMenuTemplate] != nil) + [search setSearchMenuTemplate:nil]; + + updateActiveState([search searchButtonCell], o); + + FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())]; + localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); + + [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(o)]; + [[search searchButtonCell] setControlView:nil]; + return false; +} + +const int resultsArrowWidth = 5; +void RenderThemeMacShared::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const +{ + IntSize size = sizeForSystemFont(style, resultsButtonSizes()); + style->setWidth(Length(size.width() + resultsArrowWidth, Fixed)); + style->setHeight(Length(size.height(), Fixed)); + style->setBoxShadow(nullptr); +} + +bool RenderThemeMacShared::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + Node* input = o->node()->shadowHost(); + if (!input) + input = o->node(); + if (!input->renderer()->isBox()) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + setSearchCellState(input->renderer(), r); + + NSSearchFieldCell* search = this->search(); + + updateActiveState([search searchButtonCell], o); + + if (![search searchMenuTemplate]) + [search setSearchMenuTemplate:searchMenuTemplate()]; + + GraphicsContextStateSaver stateSaver(*paintInfo.context); + float zoomLevel = o->style()->effectiveZoom(); + + FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())]; + localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); + + IntRect unzoomedRect(localBounds); + if (zoomLevel != 1.0f) { + unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); + unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); + paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); + } + + [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)]; + [[search searchButtonCell] setControlView:nil]; + + return false; +} + +#if ENABLE(DATALIST_ELEMENT) +IntSize RenderThemeMacShared::sliderTickSize() const +{ + return IntSize(1, 3); +} + +int RenderThemeMacShared::sliderTickOffsetFromTrackCenter() const +{ + return -9; +} +#endif + +const int sliderThumbWidth = 15; +const int sliderThumbHeight = 15; + +void RenderThemeMacShared::adjustSliderThumbSize(RenderStyle* style, Element*) const +{ + float zoomLevel = style->effectiveZoom(); + if (style->appearance() == SliderThumbHorizontalPart || style->appearance() == SliderThumbVerticalPart) { + style->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed)); + style->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed)); + } + +#if ENABLE(VIDEO) + adjustMediaSliderThumbSize(style); +#endif +} + +bool RenderThemeMacShared::shouldShowPlaceholderWhenFocused() const +{ +#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + return true; +#else + return false; +#endif +} + +NSPopUpButtonCell* RenderThemeMacShared::popupButton() const +{ + if (!m_popupButton) { + m_popupButton.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]); + [m_popupButton.get() setUsesItemFromMenu:NO]; + [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_popupButton.get(); +} + +NSSearchFieldCell* RenderThemeMacShared::search() const +{ + if (!m_search) { + m_search.adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]); + [m_search.get() setBezelStyle:NSTextFieldRoundedBezel]; + [m_search.get() setBezeled:YES]; + [m_search.get() setEditable:YES]; + [m_search.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_search.get(); +} + +NSMenu* RenderThemeMacShared::searchMenuTemplate() const +{ + if (!m_searchMenuTemplate) + m_searchMenuTemplate.adoptNS([[NSMenu alloc] initWithTitle:@""]); + + return m_searchMenuTemplate.get(); +} + +NSSliderCell* RenderThemeMacShared::sliderThumbHorizontal() const +{ + if (!m_sliderThumbHorizontal) { + m_sliderThumbHorizontal.adoptNS([[NSSliderCell alloc] init]); + [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider]; + [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize]; + [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_sliderThumbHorizontal.get(); +} + +NSSliderCell* RenderThemeMacShared::sliderThumbVertical() const +{ + if (!m_sliderThumbVertical) { + m_sliderThumbVertical.adoptNS([[NSSliderCell alloc] init]); + [m_sliderThumbVertical.get() setSliderType:NSLinearSlider]; + [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize]; + [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_sliderThumbVertical.get(); +} + +NSTextFieldCell* RenderThemeMacShared::textField() const +{ + if (!m_textField) { + m_textField.adoptNS([[WebCoreTextFieldCell alloc] initTextCell:@""]); + [m_textField.get() setBezeled:YES]; + [m_textField.get() setEditable:YES]; + [m_textField.get() setFocusRingType:NSFocusRingTypeExterior]; +#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 + [m_textField.get() setDrawsBackground:YES]; + [m_textField.get() setBackgroundColor:[NSColor whiteColor]]; +#else + // Post-Lion, WebCore can be in charge of paintinng the background thanks to + // the workaround in place for <rdar://problem/11385461>, which is implemented + // above as _coreUIDrawOptionsWithFrame. + [m_textField.get() setDrawsBackground:NO]; +#endif + } + + return m_textField.get(); +} + +String RenderThemeMacShared::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const +{ + if (width <= 0) + return String(); + + String strToTruncate; + if (fileList->isEmpty()) + strToTruncate = fileListDefaultLabel(multipleFilesAllowed); + else if (fileList->length() == 1) + strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(fileList->item(0)->path())]; + else + return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks); + + return StringTruncator::centerTruncate(strToTruncate, width, font, StringTruncator::EnableRoundingHacks); +} + +} // namespace WebCore diff --git a/Source/WebCore/rendering/RenderThemeWin.cpp b/Source/WebCore/rendering/RenderThemeWin.cpp index 810a1fca4..49ab18606 100644 --- a/Source/WebCore/rendering/RenderThemeWin.cpp +++ b/Source/WebCore/rendering/RenderThemeWin.cpp @@ -785,6 +785,8 @@ void RenderThemeWin::adjustMenuListButtonStyle(StyleResolver* styleResolver, Ren minHeight = max(minHeight, dropDownBoxMinHeight); style->setMinHeight(Length(minHeight, Fixed)); + + style->setLineHeight(RenderStyle::initialLineHeight()); // White-space is locked to pre style->setWhiteSpace(PRE); diff --git a/Source/WebCore/rendering/RenderTreeAsText.cpp b/Source/WebCore/rendering/RenderTreeAsText.cpp index 6c08789d4..5b4eb7358 100644 --- a/Source/WebCore/rendering/RenderTreeAsText.cpp +++ b/Source/WebCore/rendering/RenderTreeAsText.cpp @@ -726,7 +726,7 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye // Calculate the clip rects we should use. LayoutRect layerBounds; ClipRect damageRect, clipRectToApply, outlineRect; - l->calculateRects(rootLayer, 0, TemporaryClipRects, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); + l->calculateRects(RenderLayer::ClipRectsContext(rootLayer, 0, TemporaryClipRects), paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); // Ensure our lists are up-to-date. l->updateLayerListsIfNeeded(); diff --git a/Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp b/Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp index 54f807057..c23a9de20 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp @@ -44,6 +44,7 @@ using namespace MathMLNames; RenderMathMLBlock::RenderMathMLBlock(Node* container) : RenderFlexibleBox(container) + , m_ignoreInAccessibilityTree(false) , m_intrinsicPaddingBefore(0) , m_intrinsicPaddingAfter(0) , m_intrinsicPaddingStart(0) diff --git a/Source/WebCore/rendering/mathml/RenderMathMLBlock.h b/Source/WebCore/rendering/mathml/RenderMathMLBlock.h index 36e62ad67..51e80ec0a 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLBlock.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLBlock.h @@ -48,6 +48,12 @@ public: virtual bool isRenderMathMLOperator() const { return false; } virtual bool isRenderMathMLRow() const { return false; } virtual bool isRenderMathMLMath() const { return false; } + virtual bool isRenderMathMLFenced() const { return false; } + virtual bool isRenderMathMLFraction() const { return false; } + virtual bool isRenderMathMLRoot() const { return false; } + virtual bool isRenderMathMLSquareRoot() const { return false; } + virtual bool isRenderMathMLSubSup() const { return false; } + virtual bool isRenderMathMLUnderOver() const { return false; } // MathML defines an "embellished operator" as roughly an <mo> that may have subscripts, // superscripts, underscripts, overscripts, or a denominator (as in d/dx, where "d" is some @@ -87,8 +93,12 @@ public: // Create a new RenderMathMLBlock, with a new style inheriting from this->style(). RenderMathMLBlock* createAnonymousMathMLBlock(EDisplay = FLEX); + void setIgnoreInAccessibilityTree(bool flag) { m_ignoreInAccessibilityTree = flag; } + bool ignoreInAccessibilityTree() const { return m_ignoreInAccessibilityTree; } + private: virtual const char* renderName() const OVERRIDE; + bool m_ignoreInAccessibilityTree; protected: // Set our logical width to a large value, and compute our children's preferred logical heights. diff --git a/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp b/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp index f35c336eb..96f6cbabc 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp @@ -82,22 +82,23 @@ void RenderMathMLFenced::updateFromElement() makeFences(); } -RenderMathMLOperator* RenderMathMLFenced::createMathMLOperator(UChar uChar, OperatorType operatorType) +RenderMathMLOperator* RenderMathMLFenced::createMathMLOperator(UChar uChar, RenderMathMLOperator::OperatorType operatorType) { RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), FLEX); newStyle->setFlexDirection(FlowColumn); - newStyle->setMarginEnd(Length((operatorType == Fence ? gFenceMarginEms : gSeparatorMarginEndEms) * style()->fontSize(), Fixed)); - if (operatorType == Fence) + newStyle->setMarginEnd(Length((operatorType == RenderMathMLOperator::Fence ? gFenceMarginEms : gSeparatorMarginEndEms) * style()->fontSize(), Fixed)); + if (operatorType == RenderMathMLOperator::Fence) newStyle->setMarginStart(Length(gFenceMarginEms * style()->fontSize(), Fixed)); RenderMathMLOperator* newOperator = new (renderArena()) RenderMathMLOperator(node() /* "almost anonymous" */, uChar); + newOperator->setOperatorType(operatorType); newOperator->setStyle(newStyle.release()); return newOperator; } void RenderMathMLFenced::makeFences() { - RenderMathMLRow::addChild(createMathMLOperator(m_open, Fence), firstChild()); - m_closeFenceRenderer = createMathMLOperator(m_close, Fence); + RenderMathMLRow::addChild(createMathMLOperator(m_open, RenderMathMLOperator::Fence), firstChild()); + m_closeFenceRenderer = createMathMLOperator(m_close, RenderMathMLOperator::Fence); RenderMathMLRow::addChild(m_closeFenceRenderer); } @@ -132,7 +133,7 @@ void RenderMathMLFenced::addChild(RenderObject* child, RenderObject* beforeChild else separator = (*m_separators.get())[count - 1]; - separatorRenderer = createMathMLOperator(separator, Separator); + separatorRenderer = createMathMLOperator(separator, RenderMathMLOperator::Separator); } } diff --git a/Source/WebCore/rendering/mathml/RenderMathMLFenced.h b/Source/WebCore/rendering/mathml/RenderMathMLFenced.h index 0f0cfff01..a8b73a9eb 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLFenced.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLFenced.h @@ -28,6 +28,7 @@ #if ENABLE(MATHML) +#include "RenderMathMLOperator.h" #include "RenderMathMLRow.h" namespace WebCore { @@ -39,11 +40,10 @@ public: virtual void updateFromElement(); private: + virtual bool isRenderMathMLFenced() const { return true; } virtual const char* renderName() const { return "RenderMathMLFenced"; } - // FIXME: OperatorType here will go away when default operator margins are determined by the MathML operator dictionary. - enum OperatorType { Separator, Fence }; - RenderMathMLOperator* createMathMLOperator(UChar, OperatorType); + RenderMathMLOperator* createMathMLOperator(UChar, RenderMathMLOperator::OperatorType); void makeFences(); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; diff --git a/Source/WebCore/rendering/mathml/RenderMathMLFraction.h b/Source/WebCore/rendering/mathml/RenderMathMLFraction.h index 4c10e361a..1ec4a0634 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLFraction.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLFraction.h @@ -47,6 +47,7 @@ protected: virtual void layout(); private: + virtual bool isRenderMathMLFraction() const { return true; } void fixChildStyle(RenderObject* child); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; diff --git a/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp b/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp index 6655cce9a..bde8baf64 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp @@ -43,6 +43,7 @@ RenderMathMLOperator::RenderMathMLOperator(Element* element) : RenderMathMLBlock(element) , m_stretchHeight(0) , m_operator(0) + , m_operatorType(Default) { } @@ -50,6 +51,7 @@ RenderMathMLOperator::RenderMathMLOperator(Node* node, UChar operatorChar) : RenderMathMLBlock(node) , m_stretchHeight(0) , m_operator(convertHyphenMinusToMinusSign(operatorChar)) + , m_operatorType(Default) { } @@ -201,6 +203,8 @@ void RenderMathMLOperator::updateFromElement() if (stretchDisabled || !shouldStack) { m_isStacked = false; RenderBlock* container = new (renderArena()) RenderMathMLBlock(node()); + // This container doesn't offer any useful information to accessibility. + toRenderMathMLBlock(container)->setIgnoreInAccessibilityTree(true); RefPtr<RenderStyle> newStyle = RenderStyle::create(); newStyle->inheritFrom(style()); @@ -293,6 +297,7 @@ PassRefPtr<RenderStyle> RenderMathMLOperator::createStackableStyle(int maxHeight RenderBlock* RenderMathMLOperator::createGlyph(UChar glyph, int maxHeightForRenderer, int charRelative) { RenderBlock* container = new (renderArena()) RenderMathMLBlock(node()); + toRenderMathMLBlock(container)->setIgnoreInAccessibilityTree(true); container->setStyle(createStackableStyle(maxHeightForRenderer)); addChild(container); RenderBlock* parent = container; diff --git a/Source/WebCore/rendering/mathml/RenderMathMLOperator.h b/Source/WebCore/rendering/mathml/RenderMathMLOperator.h index 40d6b7785..75bb941de 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLOperator.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLOperator.h @@ -46,7 +46,11 @@ public: void stretchToHeight(int pixelHeight); virtual int firstLineBoxBaseline() const OVERRIDE; - + + enum OperatorType { Default, Separator, Fence }; + void setOperatorType(OperatorType type) { m_operatorType = type; } + OperatorType operatorType() const { return m_operatorType; } + protected: virtual void computePreferredLogicalWidths() OVERRIDE; PassRefPtr<RenderStyle> createStackableStyle(int maxHeightForRenderer); @@ -62,6 +66,7 @@ private: int m_stretchHeight; bool m_isStacked; UChar m_operator; + OperatorType m_operatorType; }; inline RenderMathMLOperator* toRenderMathMLOperator(RenderMathMLBlock* block) diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRoot.h b/Source/WebCore/rendering/mathml/RenderMathMLRoot.h index 2ae303aa8..99cd36594 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLRoot.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLRoot.h @@ -45,6 +45,7 @@ protected: virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; private: + virtual bool isRenderMathMLRoot() const { return true; } virtual const char* renderName() const { return "RenderMathMLRoot"; } virtual void computePreferredLogicalWidths() OVERRIDE; diff --git a/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h b/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h index 90e186c6b..39e0aa72c 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h @@ -38,6 +38,7 @@ public: RenderMathMLSquareRoot(Element*); private: + virtual bool isRenderMathMLSquareRoot() const { return true; } virtual const char* renderName() const { return "RenderMathMLSquareRoot"; } }; diff --git a/Source/WebCore/rendering/mathml/RenderMathMLSubSup.h b/Source/WebCore/rendering/mathml/RenderMathMLSubSup.h index 640a86e01..082f1a339 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLSubSup.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLSubSup.h @@ -44,7 +44,9 @@ protected: virtual void layout(); private: + virtual bool isRenderMathMLSubSup() const { return true; } void fixAnonymousStyles(); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; virtual const char* renderName() const { return "RenderMathMLSubSup"; } diff --git a/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.h b/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.h index caf4fc499..4608145c2 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.h @@ -41,6 +41,7 @@ public: virtual int firstLineBoxBaseline() const OVERRIDE; private: + virtual bool isRenderMathMLUnderOver() const { return true; } virtual const char* renderName() const { return "RenderMathMLUnderOver"; } enum UnderOverType { Under, Over, UnderOver }; diff --git a/Source/WebCore/rendering/style/BasicShapes.cpp b/Source/WebCore/rendering/style/BasicShapes.cpp index 29ca45d01..b21358fdc 100644 --- a/Source/WebCore/rendering/style/BasicShapes.cpp +++ b/Source/WebCore/rendering/style/BasicShapes.cpp @@ -36,6 +36,20 @@ namespace WebCore { +bool BasicShape::canBlend(const BasicShape* other) const +{ + // FIXME: Support animations between different shapes in the future. + if (type() != other->type()) + return false; + + // Just polygons with same number of vertices can be animated. + if (type() == BasicShape::BASIC_SHAPE_POLYGON + && static_cast<const BasicShapePolygon*>(this)->values().size() != static_cast<const BasicShapePolygon*>(other)->values().size()) + return false; + + return true; +} + void BasicShapeRectangle::path(Path& path, const FloatRect& boundingBox) { ASSERT(path.isEmpty()); @@ -47,6 +61,23 @@ void BasicShapeRectangle::path(Path& path, const FloatRect& boundingBox) m_cornerRadiusY.isUndefined() ? 0 : floatValueForLength(m_cornerRadiusY, boundingBox.height()))); } +PassRefPtr<BasicShape> BasicShapeRectangle::blend(const BasicShape* other, double progress) const +{ + ASSERT(type() == other->type()); + + const BasicShapeRectangle* o = static_cast<const BasicShapeRectangle*>(other); + RefPtr<BasicShapeRectangle> result = BasicShapeRectangle::create(); + result->setX(m_x.blend(o->x(), progress)); + result->setY(m_y.blend(o->y(), progress)); + result->setWidth(m_width.blend(o->width(), progress)); + result->setHeight(m_height.blend(o->height(), progress)); + if (!m_cornerRadiusX.isUndefined() && !o->cornerRadiusX().isUndefined()) + result->setCornerRadiusX(m_cornerRadiusX.blend(o->cornerRadiusX(), progress)); + if (!m_cornerRadiusY.isUndefined() && !o->cornerRadiusY().isUndefined()) + result->setCornerRadiusY(m_cornerRadiusY.blend(o->cornerRadiusY(), progress)); + return result.release(); +} + void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox) { ASSERT(path.isEmpty()); @@ -60,6 +91,18 @@ void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox) radius * 2)); } +PassRefPtr<BasicShape> BasicShapeCircle::blend(const BasicShape* other, double progress) const +{ + ASSERT(type() == other->type()); + + const BasicShapeCircle* o = static_cast<const BasicShapeCircle*>(other); + RefPtr<BasicShapeCircle> result = BasicShapeCircle::create(); + result->setCenterX(m_centerX.blend(o->centerX(), progress)); + result->setCenterY(m_centerY.blend(o->centerY(), progress)); + result->setRadius(m_radius.blend(o->radius(), progress)); + return result.release(); +} + void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox) { ASSERT(path.isEmpty()); @@ -73,6 +116,19 @@ void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox) radiusY * 2)); } +PassRefPtr<BasicShape> BasicShapeEllipse::blend(const BasicShape* other, double progress) const +{ + ASSERT(type() == other->type()); + + const BasicShapeEllipse* o = static_cast<const BasicShapeEllipse*>(other); + RefPtr<BasicShapeEllipse> result = BasicShapeEllipse::create(); + result->setCenterX(m_centerX.blend(o->centerX(), progress)); + result->setCenterY(m_centerY.blend(o->centerY(), progress)); + result->setRadiusX(m_radiusX.blend(o->radiusX(), progress)); + result->setRadiusY(m_radiusY.blend(o->radiusY(), progress)); + return result.release(); +} + void BasicShapePolygon::path(Path& path, const FloatRect& boundingBox) { ASSERT(path.isEmpty()); @@ -90,4 +146,27 @@ void BasicShapePolygon::path(Path& path, const FloatRect& boundingBox) } path.closeSubpath(); } + +PassRefPtr<BasicShape> BasicShapePolygon::blend(const BasicShape* other, double progress) const +{ + ASSERT(type() == other->type()); + + const BasicShapePolygon* o = static_cast<const BasicShapePolygon*>(other); + ASSERT(m_values.size() == o->values().size()); + ASSERT(!(m_values.size() % 2)); + + size_t length = m_values.size(); + RefPtr<BasicShapePolygon> result = BasicShapePolygon::create(); + if (!length) + return result.release(); + + result->setWindRule(o->windRule()); + + for (size_t i = 0; i < length; i = i + 2) { + result->appendPoint(m_values.at(i).blend(o->values().at(i), progress), + m_values.at(i + 1).blend(o->values().at(i + 1), progress)); + } + + return result.release(); +} } diff --git a/Source/WebCore/rendering/style/BasicShapes.h b/Source/WebCore/rendering/style/BasicShapes.h index ad1182676..171d9c1f6 100644 --- a/Source/WebCore/rendering/style/BasicShapes.h +++ b/Source/WebCore/rendering/style/BasicShapes.h @@ -52,8 +52,11 @@ public: BASIC_SHAPE_POLYGON = 4 }; + bool canBlend(const BasicShape*) const; + virtual void path(Path&, const FloatRect&) = 0; virtual WindRule windRule() const { return RULE_NONZERO; } + virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const = 0; virtual Type type() const = 0; protected: @@ -78,7 +81,8 @@ public: void setCornerRadiusX(Length radiusX) { m_cornerRadiusX = radiusX; } void setCornerRadiusY(Length radiusY) { m_cornerRadiusY = radiusY; } - virtual void path(Path&, const FloatRect&); + virtual void path(Path&, const FloatRect&) OVERRIDE; + virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE; virtual Type type() const { return BASIC_SHAPE_RECTANGLE; } private: @@ -107,7 +111,8 @@ public: void setCenterY(Length centerY) { m_centerY = centerY; } void setRadius(Length radius) { m_radius = radius; } - virtual void path(Path&, const FloatRect&); + virtual void path(Path&, const FloatRect&) OVERRIDE; + virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE; virtual Type type() const { return BASIC_SHAPE_CIRCLE; } private: @@ -132,7 +137,8 @@ public: void setRadiusX(Length radiusX) { m_radiusX = radiusX; } void setRadiusY(Length radiusY) { m_radiusY = radiusY; } - virtual void path(Path&, const FloatRect&); + virtual void path(Path&, const FloatRect&) OVERRIDE; + virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE; virtual Type type() const { return BASIC_SHAPE_ELLIPSE; } private: @@ -155,7 +161,9 @@ public: void setWindRule(WindRule windRule) { m_windRule = windRule; } void appendPoint(Length x, Length y) { m_values.append(x); m_values.append(y); } - virtual void path(Path&, const FloatRect&); + virtual void path(Path&, const FloatRect&) OVERRIDE; + virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE; + virtual WindRule windRule() const { return m_windRule; } virtual Type type() const { return BASIC_SHAPE_POLYGON; } diff --git a/Source/WebCore/rendering/style/ExclusionShapeValue.h b/Source/WebCore/rendering/style/ExclusionShapeValue.h new file mode 100644 index 000000000..5a533af8f --- /dev/null +++ b/Source/WebCore/rendering/style/ExclusionShapeValue.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ExclusionShapeValue_h +#define ExclusionShapeValue_h + +#include "BasicShapes.h" +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +class ExclusionShapeValue : public RefCounted<ExclusionShapeValue> { +public: + enum ExclusionShapeValueType { + // The AUTO value is defined by a null ExclusionShapeValue* + SHAPE, + OUTSIDE + }; + + static PassRefPtr<ExclusionShapeValue> createShapeValue(PassRefPtr<BasicShape> shape) + { + return adoptRef(new ExclusionShapeValue(shape)); + } + + static PassRefPtr<ExclusionShapeValue> createOutsideValue() + { + return adoptRef(new ExclusionShapeValue(OUTSIDE)); + } + + ExclusionShapeValueType type() const { return m_type; } + BasicShape* shape() const { return m_shape.get(); } + bool operator==(const ExclusionShapeValue& other) const { return type() == other.type(); } + +private: + ExclusionShapeValue(PassRefPtr<BasicShape> shape) : m_type(SHAPE), m_shape(shape) { } + ExclusionShapeValue(ExclusionShapeValueType type) : m_type(type) { } + ExclusionShapeValueType m_type; + RefPtr<BasicShape> m_shape; +}; + +} + +#endif diff --git a/Source/WebCore/rendering/style/GridPosition.h b/Source/WebCore/rendering/style/GridPosition.h new file mode 100644 index 000000000..3f8fe974d --- /dev/null +++ b/Source/WebCore/rendering/style/GridPosition.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GridPosition_h +#define GridPosition_h + +namespace WebCore { + +enum GridPositionType { + AutoPosition, + IntegerPosition +}; + +class GridPosition { +public: + GridPosition() + : m_type(AutoPosition) + , m_integerPosition(0) + { + } + + bool isPositive() const { return integerPosition() > 0; } + + GridPositionType type() const { return m_type; } + bool isAuto() const { return m_type == AutoPosition; } + + void setIntegerPosition(int position) + { + m_type = IntegerPosition; + m_integerPosition = position; + } + + int integerPosition() const + { + ASSERT(type() == IntegerPosition); + return m_integerPosition; + } + + bool operator==(const GridPosition& other) const + { + return m_type == other.m_type && m_integerPosition == other.m_integerPosition; + } + +private: + GridPositionType m_type; + // FIXME: This should probably be a size_t but the spec currently allows any <integer>. + int m_integerPosition; +}; + +} // namespace WebCore + +#endif // GridPosition_h diff --git a/Source/WebCore/rendering/style/RenderStyle.cpp b/Source/WebCore/rendering/style/RenderStyle.cpp index 179d32549..d7f41816a 100644 --- a/Source/WebCore/rendering/style/RenderStyle.cpp +++ b/Source/WebCore/rendering/style/RenderStyle.cpp @@ -397,8 +397,8 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon if (rareNonInheritedData->m_wrapFlow != other->rareNonInheritedData->m_wrapFlow || rareNonInheritedData->m_wrapThrough != other->rareNonInheritedData->m_wrapThrough - || rareNonInheritedData->m_wrapMargin != other->rareNonInheritedData->m_wrapMargin - || rareNonInheritedData->m_wrapPadding != other->rareNonInheritedData->m_wrapPadding) + || rareNonInheritedData->m_shapeMargin != other->rareNonInheritedData->m_shapeMargin + || rareNonInheritedData->m_shapePadding != other->rareNonInheritedData->m_shapePadding) return StyleDifferenceLayout; if (rareNonInheritedData->m_deprecatedFlexibleBox.get() != other->rareNonInheritedData->m_deprecatedFlexibleBox.get() diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h index a1db870ac..31996fa05 100644 --- a/Source/WebCore/rendering/style/RenderStyle.h +++ b/Source/WebCore/rendering/style/RenderStyle.h @@ -34,6 +34,7 @@ #include "ColorSpace.h" #include "CounterDirectives.h" #include "DataRef.h" +#include "ExclusionShapeValue.h" #include "FontBaseline.h" #include "FontDescription.h" #include "GraphicsTypes.h" @@ -619,6 +620,7 @@ public: ETextDecoration textDecoration() const { return static_cast<ETextDecoration>(visual->textDecoration); } #if ENABLE(CSS3_TEXT) TextDecorationStyle textDecorationStyle() const { return static_cast<TextDecorationStyle>(rareNonInheritedData->m_textDecorationStyle); } + ETextAlignLast textAlignLast() const { return static_cast<ETextAlignLast>(rareInheritedData->m_textAlignLast); } #else TextDecorationStyle textDecorationStyle() const { return TextDecorationStyleSolid; } #endif // CSS3_TEXT @@ -816,8 +818,8 @@ public: const Vector<Length>& gridColumns() const { return rareNonInheritedData->m_grid->m_gridColumns; } const Vector<Length>& gridRows() const { return rareNonInheritedData->m_grid->m_gridRows; } - Length gridItemColumn() const { return rareNonInheritedData->m_gridItem->m_gridColumn; } - Length gridItemRow() const { return rareNonInheritedData->m_gridItem->m_gridRow; } + const GridPosition& gridItemColumn() const { return rareNonInheritedData->m_gridItem->m_gridColumn; } + const GridPosition& gridItemRow() const { return rareNonInheritedData->m_gridItem->m_gridRow; } const ShadowData* boxShadow() const { return rareNonInheritedData->m_boxShadow.get(); } void getBoxShadowExtent(LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left) const { getShadowExtent(boxShadow(), top, right, bottom, left); } @@ -1152,6 +1154,7 @@ public: void setTextDecoration(ETextDecoration v) { SET_VAR(visual, textDecoration, v); } #if ENABLE(CSS3_TEXT) void setTextDecorationStyle(TextDecorationStyle v) { SET_VAR(rareNonInheritedData, m_textDecorationStyle, v); } + void setTextAlignLast(ETextAlignLast v) { SET_VAR(rareInheritedData, m_textAlignLast, v) } #endif // CSS3_TEXT void setDirection(TextDirection v) { inherited_flags._direction = v; } void setLineHeight(Length specifiedLineHeight); @@ -1294,8 +1297,8 @@ public: void setJustifyContent(EJustifyContent p) { SET_VAR(rareNonInheritedData, m_justifyContent, p); } void setGridColumns(const Vector<Length>& lengths) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridColumns, lengths); } void setGridRows(const Vector<Length>& lengths) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridRows, lengths); } - void setGridItemColumn(const Length& columnPosition) { SET_VAR(rareNonInheritedData.access()->m_gridItem, m_gridColumn, columnPosition); } - void setGridItemRow(const Length& rowPosition) { SET_VAR(rareNonInheritedData.access()->m_gridItem, m_gridRow, rowPosition); } + void setGridItemColumn(const GridPosition& columnPosition) { SET_VAR(rareNonInheritedData.access()->m_gridItem, m_gridColumn, columnPosition); } + void setGridItemRow(const GridPosition& rowPosition) { SET_VAR(rareNonInheritedData.access()->m_gridItem, m_gridRow, rowPosition); } void setMarqueeIncrement(const Length& f) { SET_VAR(rareNonInheritedData.access()->m_marquee, increment, f); } void setMarqueeSpeed(int f) { SET_VAR(rareNonInheritedData.access()->m_marquee, speed, f); } @@ -1453,22 +1456,24 @@ public: void setKerning(SVGLength k) { accessSVGStyle()->setKerning(k); } #endif - void setShapeInside(PassRefPtr<BasicShape> shape) + void setShapeInside(PassRefPtr<ExclusionShapeValue> value) { - if (rareNonInheritedData->m_shapeInside != shape) - rareNonInheritedData.access()->m_shapeInside = shape; + if (rareNonInheritedData->m_shapeInside == value) + return; + rareNonInheritedData.access()->m_shapeInside = value; } - BasicShape* shapeInside() const { return rareNonInheritedData->m_shapeInside.get(); } + ExclusionShapeValue* shapeInside() const { return rareNonInheritedData->m_shapeInside.get(); } - void setShapeOutside(PassRefPtr<BasicShape> shape) + void setShapeOutside(PassRefPtr<ExclusionShapeValue> value) { - if (rareNonInheritedData->m_shapeOutside != shape) - rareNonInheritedData.access()->m_shapeOutside = shape; + if (rareNonInheritedData->m_shapeOutside == value) + return; + rareNonInheritedData.access()->m_shapeOutside = value; } - BasicShape* shapeOutside() const { return rareNonInheritedData->m_shapeOutside.get(); } + ExclusionShapeValue* shapeOutside() const { return rareNonInheritedData->m_shapeOutside.get(); } - static BasicShape* initialShapeInside() { return 0; } - static BasicShape* initialShapeOutside() { return 0; } + static ExclusionShapeValue* initialShapeInside() { return 0; } + static ExclusionShapeValue* initialShapeOutside() { return 0; } void setClipPath(PassRefPtr<ClipPathOperation> operation) { @@ -1479,13 +1484,13 @@ public: static ClipPathOperation* initialClipPath() { return 0; } - Length wrapPadding() const { return rareNonInheritedData->m_wrapPadding; } - void setWrapPadding(Length wrapPadding) { SET_VAR(rareNonInheritedData, m_wrapPadding, wrapPadding); } - static Length initialWrapPadding() { return Length(0, Fixed); } + Length shapePadding() const { return rareNonInheritedData->m_shapePadding; } + void setShapePadding(Length shapePadding) { SET_VAR(rareNonInheritedData, m_shapePadding, shapePadding); } + static Length initialShapePadding() { return Length(0, Fixed); } - Length wrapMargin() const { return rareNonInheritedData->m_wrapMargin; } - void setWrapMargin(Length wrapMargin) { SET_VAR(rareNonInheritedData, m_wrapMargin, wrapMargin); } - static Length initialWrapMargin() { return Length(0, Fixed); } + Length shapeMargin() const { return rareNonInheritedData->m_shapeMargin; } + void setShapeMargin(Length shapeMargin) { SET_VAR(rareNonInheritedData, m_shapeMargin, shapeMargin); } + static Length initialShapeMargin() { return Length(0, Fixed); } bool hasContent() const { return contentData(); } const ContentData* contentData() const { return rareNonInheritedData->m_content.get(); } @@ -1611,6 +1616,7 @@ public: static ETextDecoration initialTextDecoration() { return TDNONE; } #if ENABLE(CSS3_TEXT) static TextDecorationStyle initialTextDecorationStyle() { return TextDecorationStyleSolid; } + static ETextAlignLast initialTextAlignLast() { return TextAlignLastAuto; } #endif // CSS3_TEXT static float initialZoom() { return 1.0f; } static int initialOutlineOffset() { return 0; } @@ -1708,8 +1714,8 @@ public: static Vector<Length> initialGridRows() { return initialGridTrackValue(); } // 'auto' is the default. - static Length initialGridItemColumn() { return Length(); } - static Length initialGridItemRow() { return Length(); } + static GridPosition initialGridItemColumn() { return GridPosition(); } + static GridPosition initialGridItemRow() { return GridPosition(); } static unsigned initialTabSize() { return 8; } diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.h b/Source/WebCore/rendering/style/RenderStyleConstants.h index f9f320996..72e0c4c33 100644 --- a/Source/WebCore/rendering/style/RenderStyleConstants.h +++ b/Source/WebCore/rendering/style/RenderStyleConstants.h @@ -346,6 +346,12 @@ enum TextDecorationStyle { #endif // CSS3_TEXT }; +#if ENABLE(CSS3_TEXT) +enum ETextAlignLast { + TextAlignLastAuto, TextAlignLastStart, TextAlignLastEnd, TextAlignLastLeft, TextAlignLastRight, TextAlignLastCenter, TextAlignLastJustify +}; +#endif // CSS3_TEXT + enum EPageBreak { PBAUTO, PBALWAYS, PBAVOID }; diff --git a/Source/WebCore/rendering/style/StyleGridItemData.h b/Source/WebCore/rendering/style/StyleGridItemData.h index 721f18726..2f7487b86 100644 --- a/Source/WebCore/rendering/style/StyleGridItemData.h +++ b/Source/WebCore/rendering/style/StyleGridItemData.h @@ -32,7 +32,7 @@ #define StyleGridItemData_h -#include "Length.h" +#include "GridPosition.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> #include <wtf/Vector.h> @@ -54,11 +54,8 @@ public: return !(*this == o); } - // FIXME: For the moment, we only support a subset of the grammar which correspond to: - // 'auto' | <length> - // When we add more of the syntax, we will need a dedicated GridPosition class. - Length m_gridColumn; - Length m_gridRow; + GridPosition m_gridColumn; + GridPosition m_gridRow; private: StyleGridItemData(); diff --git a/Source/WebCore/rendering/style/StyleRareInheritedData.cpp b/Source/WebCore/rendering/style/StyleRareInheritedData.cpp index 168022143..b1ba5986a 100644 --- a/Source/WebCore/rendering/style/StyleRareInheritedData.cpp +++ b/Source/WebCore/rendering/style/StyleRareInheritedData.cpp @@ -95,6 +95,9 @@ StyleRareInheritedData::StyleRareInheritedData() , m_imageResolutionSource(RenderStyle::initialImageResolutionSource()) , m_imageResolutionSnap(RenderStyle::initialImageResolutionSnap()) #endif +#if ENABLE(CSS3_TEXT) + , m_textAlignLast(RenderStyle::initialTextAlignLast()) +#endif // CSS3_TEXT , hyphenationLimitBefore(-1) , hyphenationLimitAfter(-1) , hyphenationLimitLines(-1) @@ -157,6 +160,9 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o) , m_imageResolutionSource(o.m_imageResolutionSource) , m_imageResolutionSnap(o.m_imageResolutionSnap) #endif +#if ENABLE(CSS3_TEXT) + , m_textAlignLast(o.m_textAlignLast) +#endif // CSS3_TEXT , hyphenationString(o.hyphenationString) , hyphenationLimitBefore(o.hyphenationLimitBefore) , hyphenationLimitAfter(o.hyphenationLimitAfter) @@ -246,6 +252,9 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const && m_imageResolutionSnap == o.m_imageResolutionSnap && m_imageResolution == o.m_imageResolution #endif +#if ENABLE(CSS3_TEXT) + && m_textAlignLast == o.m_textAlignLast +#endif // CSS3_TEXT && m_lineSnap == o.m_lineSnap #if ENABLE(CSS_VARIABLES) && m_variables == o.m_variables diff --git a/Source/WebCore/rendering/style/StyleRareInheritedData.h b/Source/WebCore/rendering/style/StyleRareInheritedData.h index a34dfb2a3..d07e04c33 100644 --- a/Source/WebCore/rendering/style/StyleRareInheritedData.h +++ b/Source/WebCore/rendering/style/StyleRareInheritedData.h @@ -110,6 +110,9 @@ public: unsigned m_imageResolutionSource : 1; // ImageResolutionSource unsigned m_imageResolutionSnap : 1; // ImageResolutionSnap #endif +#if ENABLE(CSS3_TEXT) + unsigned m_textAlignLast : 3; // ETextAlignLast +#endif // CSS3_TEXT AtomicString hyphenationString; short hyphenationLimitBefore; diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp b/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp index 6c898960d..1c6cb1879 100644 --- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp +++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp @@ -51,8 +51,8 @@ StyleRareNonInheritedData::StyleRareNonInheritedData() , m_pageSize() , m_shapeInside(RenderStyle::initialShapeInside()) , m_shapeOutside(RenderStyle::initialShapeOutside()) - , m_wrapMargin(RenderStyle::initialWrapMargin()) - , m_wrapPadding(RenderStyle::initialWrapPadding()) + , m_shapeMargin(RenderStyle::initialShapeMargin()) + , m_shapePadding(RenderStyle::initialShapePadding()) , m_clipPath(RenderStyle::initialClipPath()) , m_visitedLinkBackgroundColor(RenderStyle::initialBackgroundColor()) , m_order(RenderStyle::initialOrder()) @@ -125,8 +125,8 @@ StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonInherited , m_pageSize(o.m_pageSize) , m_shapeInside(o.m_shapeInside) , m_shapeOutside(o.m_shapeOutside) - , m_wrapMargin(o.m_wrapMargin) - , m_wrapPadding(o.m_wrapPadding) + , m_shapeMargin(o.m_shapeMargin) + , m_shapePadding(o.m_shapePadding) , m_clipPath(o.m_clipPath) , m_visitedLinkBackgroundColor(o.m_visitedLinkBackgroundColor) , m_visitedLinkOutlineColor(o.m_visitedLinkOutlineColor) @@ -210,8 +210,8 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c && m_pageSize == o.m_pageSize && m_shapeInside == o.m_shapeInside && m_shapeOutside == o.m_shapeOutside - && m_wrapMargin == o.m_wrapMargin - && m_wrapPadding == o.m_wrapPadding + && m_shapeMargin == o.m_shapeMargin + && m_shapePadding == o.m_shapePadding && m_clipPath == o.m_clipPath && m_visitedLinkBackgroundColor == o.m_visitedLinkBackgroundColor && m_visitedLinkOutlineColor == o.m_visitedLinkOutlineColor diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h index e3784d4af..c4ac0f6f3 100644 --- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h +++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h @@ -30,6 +30,7 @@ #include "CounterDirectives.h" #include "CursorData.h" #include "DataRef.h" +#include "ExclusionShapeValue.h" #include "FillLayer.h" #include "LineClampValue.h" #include "NinePieceImage.h" @@ -137,10 +138,10 @@ public: LengthSize m_pageSize; - RefPtr<BasicShape> m_shapeInside; - RefPtr<BasicShape> m_shapeOutside; - Length m_wrapMargin; - Length m_wrapPadding; + RefPtr<ExclusionShapeValue> m_shapeInside; + RefPtr<ExclusionShapeValue> m_shapeOutside; + Length m_shapeMargin; + Length m_shapePadding; RefPtr<ClipPathOperation> m_clipPath; diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp index b4c67b9b2..019204e4e 100644 --- a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp @@ -70,7 +70,7 @@ const RenderObject* RenderSVGModelObject::pushMappingToContainer(const RenderLay // Copied from RenderBox, this method likely requires further refactoring to work easily for both SVG and CSS Box Model content. // FIXME: This may also need to move into SVGRenderSupport as the RenderBox version depends // on borderBoundingBox() which SVG RenderBox subclases (like SVGRenderBlock) do not implement. -LayoutRect RenderSVGModelObject::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, LayoutPoint*) const +LayoutRect RenderSVGModelObject::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap*) const { LayoutRect box = enclosingLayoutRect(repaintRectInLocalCoordinates()); adjustRectForOutlineAndShadow(box); diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.h b/Source/WebCore/rendering/svg/RenderSVGModelObject.h index 50e9f6860..dc2d5da39 100644 --- a/Source/WebCore/rendering/svg/RenderSVGModelObject.h +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.h @@ -53,7 +53,7 @@ public: virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const OVERRIDE; - virtual LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, LayoutPoint*) const OVERRIDE; + virtual LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap*) const OVERRIDE; virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const; virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp index 2eabeeb70..c75015d57 100644 --- a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp +++ b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp @@ -111,10 +111,12 @@ const RenderObject* SVGRenderSupport::pushMappingToContainer(const RenderObject* // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform // to map an element from SVG viewport coordinates to CSS box coordinates. // RenderSVGRoot's mapLocalToContainer method expects CSS box coordinates. - if (parent->isSVGRoot()) - geometryMap.push(object, TransformationMatrix(toRenderSVGRoot(parent)->localToBorderBoxTransform())); - else - geometryMap.push(object, LayoutSize()); + if (parent->isSVGRoot()) { + TransformationMatrix matrix(object->localToParentTransform()); + matrix.multiply(toRenderSVGRoot(parent)->localToBorderBoxTransform()); + geometryMap.push(object, matrix); + } else + geometryMap.push(object, object->localToParentTransform()); return parent; } |
