Source/WebCore/ChangeLog

 12013-05-07 Allan Sandfeld Jensen <allan.jensen@digia.com>
 2
 3 REGRESSION(SUBPIXEL_LAYOUT) Composited layers can cause one pixel shifts
 4 https://bugs.webkit.org/show_bug.cgi?id=115304
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Accelerated layers can cause blocks at subpixel offsets to shift because
 9 accumulated subpixel offsets are lost between each layers.
 10
 11 To solve this layer bounds are now calculated in LayoutUnits, and their
 12 subpixel offset used to ensure correct pixel snapping of the accelerated
 13 layer itself, and passed on to the layout of its content.
 14
 15 Test: fast/sub-pixel/sub-pixel-composited-layers.html
 16
 17 * WebCore.exp.in:
 18 * inspector/InspectorLayerTreeAgent.cpp:
 19 (WebCore::InspectorLayerTreeAgent::buildObjectForLayer):
 20 * platform/graphics/GraphicsLayer.cpp:
 21 (WebCore::GraphicsLayer::paintGraphicsLayerContents):
 22 Avoid using Layout types when the input is Int types.
 23 * platform/graphics/GraphicsLayer.h:
 24 (WebCore::GraphicsLayer::subpixelAccumulation):
 25 (WebCore::GraphicsLayer::setSubpixelAccumulation):
 26 (GraphicsLayer):
 27 * platform/graphics/LayoutPoint.h:
 28 (WebCore::LayoutPoint::fraction):
 29 (LayoutPoint):
 30 * rendering/RenderLayer.cpp:
 31 (WebCore::RenderLayer::paintLayerContents):
 32 (WebCore::RenderLayer::calculateLayerBounds):
 33 * rendering/RenderLayer.h:
 34 (RenderLayer):
 35 * rendering/RenderLayerBacking.cpp:
 36 (WebCore::RenderLayerBacking::updateCompositedBounds):
 37 (WebCore::RenderLayerBacking::updateAfterWidgetResize):
 38 (WebCore::RenderLayerBacking::updateGraphicsLayerGeometry):
 39 (WebCore::RenderLayerBacking::resetContentsRect):
 40 (WebCore::RenderLayerBacking::contentOffsetInCompostingLayer):
 41 (WebCore::RenderLayerBacking::contentsBox):
 42 (WebCore::RenderLayerBacking::backgroundBox):
 43 (WebCore::RenderLayerBacking::paintIntoLayer):
 44 (WebCore::RenderLayerBacking::paintContents):
 45 (WebCore::RenderLayerBacking::compositedBounds):
 46 (WebCore::RenderLayerBacking::setCompositedBounds):
 47 * rendering/RenderLayerBacking.h:
 48 (RenderLayerBacking):
 49 * rendering/RenderLayerCompositor.cpp:
 50 (WebCore::RenderLayerCompositor::logLayerInfo):
 51 (WebCore::RenderLayerCompositor::calculateCompositedBounds):
 52 * rendering/RenderLayerCompositor.h:
 53 * rendering/RenderTreeAsText.cpp:
 54 (WebCore::operator<<):
 55 * rendering/RenderTreeAsText.h:
 56
1572013-05-07 Mikhail Pozdnyakov <mikhail.pozdnyakov@intel.com>
258
359 HashTraits<RefPtr<P> >::PeekType should be raw pointer for better performance

Source/WebCore/WebCore.exp.in

@@__ZN7WebCore9FloatRectC1ERK6CGRect
11191119__ZN7WebCore9FloatRectC1ERKNS_7IntRectE
11201120__ZN7WebCore9FloatSizeC1ERK6CGSize
11211121__ZN7WebCore9FloatSizeC1ERKNS_7IntSizeE
 1122__ZN7WebCore9FloatRectC1ERKNS_10LayoutRectE
11221123__ZN7WebCore9FontCache13fontDataCountEv
11231124__ZN7WebCore9FontCache21inactiveFontDataCountEv
11241125__ZN7WebCore9FontCache21purgeInactiveFontDataEi

Source/WebCore/inspector/InspectorLayerTreeAgent.cpp

@@PassRefPtr<TypeBuilder::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectFo
180180 .setNodeId(idForNode(errorString, node))
181181 .setBounds(buildObjectForIntRect(enclosingIntRect(renderer->absoluteBoundingBoxRect())))
182182 .setMemory(backing->backingStoreMemoryEstimate())
183  .setCompositedBounds(buildObjectForIntRect(backing->compositedBounds()))
 183 .setCompositedBounds(buildObjectForIntRect(enclosingIntRect(backing->compositedBounds())))
184184 .setPaintCount(backing->graphicsLayer()->repaintCount());
185185
186186 if (node && node->shadowHost())

Source/WebCore/platform/graphics/GraphicsLayer.cpp

@@void GraphicsLayer::setBackgroundColor(const Color& color)
315315void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const IntRect& clip)
316316{
317317 if (m_client) {
318  LayoutSize offset = offsetFromRenderer();
 318 IntSize offset = offsetFromRenderer();
319319 context.translate(-offset);
320320
321  LayoutRect clipRect(clip);
 321 IntRect clipRect(clip);
322322 clipRect.move(offset);
323323
324  m_client->paintContents(this, context, m_paintingPhase, pixelSnappedIntRect(clipRect));
 324 m_client->paintContents(this, context, m_paintingPhase, clipRect);
325325 }
326326}
327327

Source/WebCore/platform/graphics/GraphicsLayer.h

@@public:
248248 IntSize offsetFromRenderer() const { return m_offsetFromRenderer; }
249249 void setOffsetFromRenderer(const IntSize&, ShouldSetNeedsDisplay = SetNeedsDisplay);
250250
 251 LayoutSize subpixelAccumulation() const { return m_subpixelAccumulation; }
 252 void setSubpixelAccumulation(const LayoutSize& subpixelAccumulation) { m_subpixelAccumulation = subpixelAccumulation; }
 253
251254 // The position of the layer (the location of its top-left corner in its parent)
252255 const FloatPoint& position() const { return m_position; }
253256 virtual void setPosition(const FloatPoint& p) { m_position = p; }

@@protected:
494497
495498 // Offset from the owning renderer
496499 IntSize m_offsetFromRenderer;
497 
 500
 501 // Accumulated subpixel error to be used by subpixel layout of the content.
 502 LayoutSize m_subpixelAccumulation;
 503
498504 // Position is relative to the parent GraphicsLayer
499505 FloatPoint m_position;
500506 FloatPoint3D m_anchorPoint;

Source/WebCore/platform/graphics/LayoutPoint.h

@@public:
9090 return LayoutPoint(m_y, m_x);
9191 }
9292
 93 LayoutPoint fraction() const
 94 {
 95 return LayoutPoint(m_x.fraction(), m_y.fraction());
 96 }
 97
9398#if PLATFORM(QT)
9499 explicit LayoutPoint(const QPoint&);
95100 explicit LayoutPoint(const QPointF&);

Source/WebCore/rendering/RenderLayer.cpp

@@void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti
37173717 LayoutPoint offsetFromRoot;
37183718 convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot);
37193719
3720  IntRect rootRelativeBounds;
 3720 LayoutRect rootRelativeBounds;
37213721 bool rootRelativeBoundsComputed = false;
37223722
37233723 bool didQuantizeFonts = true;

@@IntRect RenderLayer::absoluteBoundingBox() const
53395339 return pixelSnappedIntRect(boundingBox(root()));
53405340}
53415341
5342 IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot, CalculateLayerBoundsFlags flags) const
 5342LayoutRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot, CalculateLayerBoundsFlags flags) const
53435343{
53445344 if (!isSelfPaintingLayer())
5345  return IntRect();
 5345 return LayoutRect();
53465346
53475347 // FIXME: This could be improved to do a check like hasVisibleNonCompositingDescendantLayers() (bug 92580).
53485348 if ((flags & ExcludeHiddenDescendants) && this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant())
5349  return IntRect();
 5349 return LayoutRect();
53505350
53515351 RenderLayerModelObject* renderer = this->renderer();
53525352

@@IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
53865386 LayoutPoint ancestorRelOffset;
53875387 convertToLayerCoords(ancestorLayer, ancestorRelOffset);
53885388 localClipRect.moveBy(ancestorRelOffset);
5389  return pixelSnappedIntRect(localClipRect);
 5389 return localClipRect;
53905390 }
53915391 }
53925392

@@IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
53975397
53985398 if (RenderLayer* reflection = reflectionLayer()) {
53995399 if (!reflection->isComposited()) {
5400  IntRect childUnionBounds = reflection->calculateLayerBounds(this, 0, descendantFlags);
 5400 LayoutRect childUnionBounds = reflection->calculateLayerBounds(this, 0, descendantFlags);
54015401 unionBounds.unite(childUnionBounds);
54025402 }
54035403 }

@@IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
54135413 for (size_t i = 0; i < listSize; ++i) {
54145414 RenderLayer* curLayer = negZOrderList->at(i);
54155415 if (flags & IncludeCompositedDescendants || !curLayer->isComposited()) {
5416  IntRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
 5416 LayoutRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
54175417 unionBounds.unite(childUnionBounds);
54185418 }
54195419 }

@@IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
54245424 for (size_t i = 0; i < listSize; ++i) {
54255425 RenderLayer* curLayer = posZOrderList->at(i);
54265426 if (flags & IncludeCompositedDescendants || !curLayer->isComposited()) {
5427  IntRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
 5427 LayoutRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
54285428 unionBounds.unite(childUnionBounds);
54295429 }
54305430 }

@@IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
54355435 for (size_t i = 0; i < listSize; ++i) {
54365436 RenderLayer* curLayer = normalFlowList->at(i);
54375437 if (flags & IncludeCompositedDescendants || !curLayer->isComposited()) {
5438  IntRect curAbsBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
 5438 LayoutRect curAbsBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
54395439 unionBounds.unite(curAbsBounds);
54405440 }
54415441 }

@@IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
54625462 convertToLayerCoords(ancestorLayer, ancestorRelOffset);
54635463 unionBounds.moveBy(ancestorRelOffset);
54645464
5465  return pixelSnappedIntRect(unionBounds);
 5465 return unionBounds;
54665466}
54675467
54685468void RenderLayer::clearClipRectsIncludingDescendants(ClipRectsType typeToClear)

Source/WebCore/rendering/RenderLayer.h

@@public:
701701#endif
702702
703703 // Can pass offsetFromRoot if known.
704  IntRect calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot = 0, CalculateLayerBoundsFlags = DefaultCalculateLayerBoundsFlags) const;
 704 LayoutRect calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot = 0, CalculateLayerBoundsFlags = DefaultCalculateLayerBoundsFlags) const;
705705
706706 // WARNING: This method returns the offset for the parent as this is what updateLayerPositions expects.
707707 LayoutPoint computeOffsetFromRoot(bool& hasLayerOffset) const;

Source/WebCore/rendering/RenderLayerBacking.cpp

@@bool RenderLayerBacking::shouldClipCompositedBounds() const
426426
427427void RenderLayerBacking::updateCompositedBounds()
428428{
429  IntRect layerBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer);
 429 LayoutRect layerBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer);
430430
431431 // Clip to the size of the document or enclosing overflow-scroll layer.
432432 // If this or an ancestor is transformed, we can't currently compute the correct rect to intersect with.

@@void RenderLayerBacking::updateCompositedBounds()
448448 m_owningLayer->convertToLayerCoords(rootLayer, delta);
449449 clippingBounds.move(-delta.x(), -delta.y());
450450
451  layerBounds.intersect(pixelSnappedIntRect(clippingBounds));
 451 layerBounds.intersect(clippingBounds);
452452 m_boundsConstrainedByClipping = true;
453453 } else
454454 m_boundsConstrainedByClipping = false;

@@void RenderLayerBacking::updateAfterWidgetResize()
471471 if (renderer()->isRenderPart()) {
472472 if (RenderLayerCompositor* innerCompositor = RenderLayerCompositor::frameContentsCompositor(toRenderPart(renderer()))) {
473473 innerCompositor->frameViewDidChangeSize();
474  innerCompositor->frameViewDidChangeLocation(contentsBox().location());
 474 innerCompositor->frameViewDidChangeLocation(flooredIntPoint(contentsBox().location()));
475475 }
476476 }
477477}

@@void RenderLayerBacking::updateGraphicsLayerGeometry()
647647 ancestorCompositingBounds = pixelSnappedIntRect(compAncestor->backing()->compositedBounds());
648648 }
649649
650  IntRect localCompositingBounds = pixelSnappedIntRect(compositedBounds());
651 
652  IntRect relativeCompositingBounds(localCompositingBounds);
653  IntPoint delta;
654  m_owningLayer->convertToPixelSnappedLayerCoords(compAncestor, delta);
 650 LayoutRect localCompositingBounds = compositedBounds();
 651 LayoutRect relativeCompositingBounds(localCompositingBounds);
 652 LayoutPoint delta;
 653 m_owningLayer->convertToLayerCoords(compAncestor, delta);
655654 relativeCompositingBounds.moveBy(delta);
 655 // We must move the bounds by the subpixel part of delta,
 656 // so that they can be pixel snapped to actual pixels.
 657 localCompositingBounds.moveBy(delta.fraction());
 658
 659 IntPoint pixelDelta = flooredIntPoint(delta);
 660 IntRect localPixelCompositingBounds = pixelSnappedIntRect(localCompositingBounds);
 661 IntRect relativePixelCompositingBounds = pixelSnappedIntRect(relativeCompositingBounds);
656662
657663 IntPoint graphicsLayerParentLocation;
658664 if (compAncestor && compAncestor->backing()->hasClippingLayer()) {

@@void RenderLayerBacking::updateGraphicsLayerGeometry()
683689 m_ancestorClippingLayer->setSize(parentClipRect.size());
684690
685691 // backgroundRect is relative to compAncestor, so subtract deltaX/deltaY to get back to local coords.
686  m_ancestorClippingLayer->setOffsetFromRenderer(parentClipRect.location() - delta);
 692 m_ancestorClippingLayer->setOffsetFromRenderer(parentClipRect.location() - pixelDelta);
687693
688694 // The primary layer is then parented in, and positioned relative to this clipping layer.
689695 graphicsLayerParentLocation = parentClipRect.location();
690696 }
691697
692  FloatSize contentsSize = relativeCompositingBounds.size();
 698 FloatSize contentsSize = relativePixelCompositingBounds.size();
693699
694700 if (m_contentsContainmentLayer) {
695701 m_contentsContainmentLayer->setPreserves3D(preserves3D);
696  m_contentsContainmentLayer->setPosition(FloatPoint(relativeCompositingBounds.location() - graphicsLayerParentLocation));
 702 m_contentsContainmentLayer->setPosition(FloatPoint(relativePixelCompositingBounds.location() - graphicsLayerParentLocation));
697703 // Use the same size as m_graphicsLayer so transforms behave correctly.
698704 m_contentsContainmentLayer->setSize(contentsSize);
699  graphicsLayerParentLocation = relativeCompositingBounds.location();
 705 graphicsLayerParentLocation = relativePixelCompositingBounds.location();
700706 }
701707
702  m_graphicsLayer->setPosition(FloatPoint(relativeCompositingBounds.location() - graphicsLayerParentLocation));
703  m_graphicsLayer->setOffsetFromRenderer(toIntSize(localCompositingBounds.location()));
704 
 708 m_graphicsLayer->setPosition(FloatPoint(relativePixelCompositingBounds.location() - graphicsLayerParentLocation));
 709 m_graphicsLayer->setOffsetFromRenderer(toIntSize(localPixelCompositingBounds.location()));
 710 m_graphicsLayer->setSubpixelAccumulation(toLayoutSize(delta.fraction()));
 711
705712 FloatSize oldSize = m_graphicsLayer->size();
706713 if (oldSize != contentsSize) {
707714 m_graphicsLayer->setSize(contentsSize);

@@void RenderLayerBacking::updateGraphicsLayerGeometry()
721728 IntRect clippingBox;
722729 if (GraphicsLayer* clipLayer = clippingLayer()) {
723730 clippingBox = clipBox(toRenderBox(renderer()));
724  clipLayer->setPosition(FloatPoint(clippingBox.location() - localCompositingBounds.location()));
 731 clipLayer->setPosition(FloatPoint(clippingBox.location() - localPixelCompositingBounds.location()));
725732 clipLayer->setSize(clippingBox.size());
726733 clipLayer->setOffsetFromRenderer(toIntSize(clippingBox.location()));
727734 }

@@void RenderLayerBacking::updateGraphicsLayerGeometry()
739746 const IntRect borderBox = toRenderBox(renderer())->pixelSnappedBorderBoxRect();
740747
741748 // Get layout bounds in the coords of compAncestor to match relativeCompositingBounds.
742  IntRect layerBounds = IntRect(delta, borderBox.size());
 749 IntRect layerBounds(pixelDelta, borderBox.size());
743750
744751 // Update properties that depend on layer dimensions
745752 FloatPoint3D transformOrigin = computeTransformOrigin(borderBox);

@@void RenderLayerBacking::updateInternalHierarchy()
949956
950957void RenderLayerBacking::resetContentsRect()
951958{
952  IntRect rect = contentsBox();
 959 IntRect rect = pixelSnappedIntRect(contentsBox());
953960 m_graphicsLayer->setContentsRect(rect);
954961 m_graphicsLayer->setContentsTileSize(IntSize());
955962 m_graphicsLayer->setContentsTilePhase(IntPoint());

@@FloatPoint RenderLayerBacking::computePerspectiveOrigin(const IntRect& borderBox
17701777}
17711778
17721779// Return the offset from the top-left of this compositing layer at which the renderer's contents are painted.
1773 IntSize RenderLayerBacking::contentOffsetInCompostingLayer() const
 1780LayoutSize RenderLayerBacking::contentOffsetInCompostingLayer() const
17741781{
1775  return IntSize(-m_compositedBounds.x(), -m_compositedBounds.y());
 1782 return LayoutSize(-m_compositedBounds.x(), -m_compositedBounds.y());
17761783}
17771784
1778 IntRect RenderLayerBacking::contentsBox() const
 1785LayoutRect RenderLayerBacking::contentsBox() const
17791786{
17801787 if (!renderer()->isBox())
1781  return IntRect();
 1788 return LayoutRect();
17821789
1783  IntRect contentsRect;
 1790 LayoutRect contentsRect;
17841791#if ENABLE(VIDEO)
17851792 if (renderer()->isVideo()) {
17861793 RenderVideo* videoRenderer = toRenderVideo(renderer());
17871794 contentsRect = videoRenderer->videoBox();
17881795 } else
17891796#endif
1790  contentsRect = pixelSnappedIntRect(toRenderBox(renderer())->contentBoxRect());
 1797 contentsRect = toRenderBox(renderer())->contentBoxRect();
17911798
17921799 contentsRect.move(contentOffsetInCompostingLayer());
17931800 return contentsRect;

@@IntRect RenderLayerBacking::backgroundBox() const
18151822 if (!renderer()->isBox())
18161823 return IntRect();
18171824
1818  IntRect pixelSnappedBackgroundBox = pixelSnappedIntRect(backgroundRectForBox(toRenderBox(renderer())));
1819  pixelSnappedBackgroundBox.move(contentOffsetInCompostingLayer());
1820  return pixelSnappedBackgroundBox;
 1825 LayoutRect backgroundBox = backgroundRectForBox(toRenderBox(renderer()));
 1826 backgroundBox.move(contentOffsetInCompostingLayer());
 1827 return pixelSnappedIntRect(backgroundBox);
18211828}
18221829
18231830GraphicsLayer* RenderLayerBacking::parentForSublayers() const

@@void RenderLayerBacking::paintIntoLayer(const GraphicsLayer* graphicsLayer, Grap
19631970 paintFlags |= RenderLayer::PaintLayerPaintingSkipRootBackground;
19641971
19651972 // FIXME: GraphicsLayers need a way to split for RenderRegions.
1966  RenderLayer::LayerPaintingInfo paintingInfo(m_owningLayer, paintDirtyRect, paintBehavior, LayoutSize());
 1973 LayoutSize subPixelAccumulation = graphicsLayer->subpixelAccumulation();
 1974 RenderLayer::LayerPaintingInfo paintingInfo(m_owningLayer, paintDirtyRect, paintBehavior, subPixelAccumulation);
19671975 m_owningLayer->paintLayerContents(context, paintingInfo, paintFlags);
19681976
19691977 if (m_owningLayer->containsDirtyOverlayScrollbars())

@@void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, Graph
20042012 // The dirtyRect is in the coords of the painting root.
20052013 IntRect dirtyRect = clip;
20062014 if (!(paintingPhase & GraphicsLayerPaintOverflowContents))
2007  dirtyRect.intersect(compositedBounds());
 2015 dirtyRect.intersect(enclosingIntRect(compositedBounds()));
20082016
20092017 // We have to use the same root as for hit testing, because both methods can compute and cache clipRects.
20102018 paintIntoLayer(graphicsLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase);

@@void RenderLayerBacking::resumeAnimations()
22402248 m_graphicsLayer->resumeAnimations();
22412249}
22422250
2243 IntRect RenderLayerBacking::compositedBounds() const
 2251LayoutRect RenderLayerBacking::compositedBounds() const
22442252{
22452253 return m_compositedBounds;
22462254}
22472255
2248 void RenderLayerBacking::setCompositedBounds(const IntRect& bounds)
 2256void RenderLayerBacking::setCompositedBounds(const LayoutRect& bounds)
22492257{
22502258 m_compositedBounds = bounds;
22512259}

Source/WebCore/rendering/RenderLayerBacking.h

@@public:
141141 void suspendAnimations(double time = 0);
142142 void resumeAnimations();
143143
144  IntRect compositedBounds() const;
145  void setCompositedBounds(const IntRect&);
 144 LayoutRect compositedBounds() const;
 145 void setCompositedBounds(const LayoutRect&);
146146 void updateCompositedBounds();
147147
148148 void updateAfterWidgetResize();

@@public:
175175 virtual void verifyNotPainting();
176176#endif
177177
178  IntRect contentsBox() const;
 178 LayoutRect contentsBox() const;
179179 IntRect backgroundBox() const;
180180
181181 // For informative purposes only.

@@private:
229229
230230 GraphicsLayerPaintingPhase paintingPhaseForPrimaryLayer() const;
231231
232  IntSize contentOffsetInCompostingLayer() const;
 232 LayoutSize contentOffsetInCompostingLayer() const;
233233 // Result is transform origin in pixels.
234234 FloatPoint3D computeTransformOrigin(const IntRect& borderBox) const;
235235 // Result is perspective origin in pixels.

@@private:
297297
298298 uint64_t m_scrollLayerID;
299299
300  IntRect m_compositedBounds;
 300 LayoutRect m_compositedBounds;
301301
302302 bool m_artificiallyInflatedBounds; // bounds had to be made non-zero to make transform-origin work
303303 bool m_boundsConstrainedByClipping;

Source/WebCore/rendering/RenderLayerCompositor.cpp

@@void RenderLayerCompositor::logLayerInfo(const RenderLayer* layer, int depth)
618618 m_secondaryBackingStoreBytes += backing->backingStoreMemoryEstimate();
619619 }
620620
621  LOG(Compositing, "%*p %dx%d %.2fKB %s(%s) %s\n", 12 + depth * 2, layer, backing->compositedBounds().width(), backing->compositedBounds().height(),
 621 LOG(Compositing, "%*p %dx%d %.2fKB %s(%s) %s\n", 12 + depth * 2, layer, backing->compositedBounds().width().round(), backing->compositedBounds().height().round(),
622622 backing->backingStoreMemoryEstimate() / 1024,
623623 backing->graphicsLayer()->contentsOpaque() ? "opaque " : "",
624624 logReasonsForCompositing(layer), layer->name().utf8().data());

@@void RenderLayerCompositor::repaintInCompositedAncestor(RenderLayer* layer, cons
773773
774774// The bounds of the GraphicsLayer created for a compositing layer is the union of the bounds of all the descendant
775775// RenderLayers that are rendered by the composited RenderLayer.
776 IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer) const
 776LayoutRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer) const
777777{
778778 if (!canBeComposited(layer))
779  return IntRect();
 779 return LayoutRect();
780780 return layer->calculateLayerBounds(ancestorLayer, 0, RenderLayer::DefaultCalculateLayerBoundsFlags | RenderLayer::ExcludeHiddenDescendants | RenderLayer::DontConstrainForMask);
781781}
782782

Source/WebCore/rendering/RenderLayerCompositor.h

@@public:
161161
162162 // Return the bounding box required for compositing layer and its childern, relative to ancestorLayer.
163163 // If layerBoundingBox is not 0, on return it contains the bounding box of this layer only.
164  IntRect calculateCompositedBounds(const RenderLayer*, const RenderLayer* ancestorLayer) const;
 164 LayoutRect calculateCompositedBounds(const RenderLayer*, const RenderLayer* ancestorLayer) const;
165165
166166 // Repaint the appropriate layers when the given RenderLayer starts or stops being composited.
167167 void repaintOnCompositingChange(RenderLayer*);

Source/WebCore/rendering/RenderTreeAsText.cpp

@@TextStream& operator<<(TextStream& ts, const IntPoint& p)
8989 return ts << "(" << p.x() << "," << p.y() << ")";
9090}
9191
 92TextStream& operator<<(TextStream& ts, const LayoutRect& r)
 93{
 94 // FIXME: These should be printed as floats. Keeping them ints for consistency with pervious test expectations.
 95 return ts << pixelSnappedIntRect(r);
 96}
 97
9298TextStream& operator<<(TextStream& ts, const LayoutPoint& p)
9399{
94100 // FIXME: These should be printed as floats. Keeping them ints for consistency with pervious test expectations.

Source/WebCore/rendering/RenderTreeAsText.h

@@class Frame;
3838class IntPoint;
3939class IntRect;
4040class LayoutPoint;
 41class LayoutRect;
4142class RenderObject;
4243class TextStream;
4344

@@static void writeRenderObject(TextStream& ts, const RenderObject& o, RenderAsTex
7172TextStream& operator<<(TextStream&, const IntPoint&);
7273TextStream& operator<<(TextStream&, const IntRect&);
7374TextStream& operator<<(TextStream&, const LayoutPoint&);
 75TextStream& operator<<(TextStream&, const LayoutRect&);
7476TextStream& operator<<(TextStream&, const FloatPoint&);
7577TextStream& operator<<(TextStream&, const FloatSize&);
7678

LayoutTests/ChangeLog

 12013-05-02 Allan Sandfeld Jensen <allan.jensen@digia.com>
 2
 3 REGRESSION(SUBPIXEL_LAYOUT) Composited layers can cause one pixel shifts
 4 https://bugs.webkit.org/show_bug.cgi?id=115304
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 * fast/sub-pixel/sub-pixel-composited-layers-expected.html: Added.
 9 * fast/sub-pixel/sub-pixel-composited-layers.html: Added.
 10
1112013-05-06 Bem Jones-Bey <bjonesbe@adobe.com>
212
313 Heap-use-after-free in WebCore::InlineFlowBox::deleteLine

LayoutTests/fast/sub-pixel/sub-pixel-composited-layers-expected.html

 1<html>
 2<head>
 3<style>
 4 #test {
 5 margin: 5px;
 6 }
 7 .container {
 8 position: absolute;
 9 opacity: 0.95;
 10 }
 11 .shifter {
 12 position: absolute;
 13 background-color: black;
 14 width: 12.5px;
 15 height: 12.5px;
 16 }
 17 .shifter8x8 {
 18 position: absolute;
 19 background-color: black;
 20 width: 16.5px;
 21 height: 16.5px;
 22 }
 23</style>
 24</head>
 25<body>
 26<div id=test>
 27</div>
 28<script>
 29 function setupGrid10x10(leftOffset, topOffset, leftFraction, topFraction)
 30 {
 31 var test = document.getElementById('test');
 32 for (var i = 0; i < 10; i++) {
 33 if (i == 5)
 34 topOffset += 5;
 35 var leftOffsetj = leftOffset;
 36 for (var j = 0; j < 10; j++) {
 37 if (j == 5)
 38 leftOffsetj += 5;
 39 var container = document.createElement("div");
 40 var shifter = document.createElement("div");
 41 container.setAttribute('class', 'container');
 42 shifter.setAttribute('class', 'shifter');
 43 container.style.left = (leftOffsetj + j * 16 + i * leftFraction) + "px"
 44 container.style.top = (topOffset + i * 16 + i * topFraction) + "px"
 45 shifter.style.left = (5 + j * leftFraction) + "px"
 46 shifter.style.top = (5 + j * topFraction) + "px"
 47 container.appendChild(shifter);
 48 test.appendChild(container);
 49 }
 50 }
 51 }
 52
 53 function setupGrid8x8(leftOffset, topOffset, leftFraction, topFraction)
 54 {
 55 var test = document.getElementById('test');
 56 for (var i = 0; i < 8; i++) {
 57 if (i == 4)
 58 topOffset += 5;
 59 var leftOffsetj = leftOffset;
 60 for (var j = 0; j < 8; j++) {
 61 if (j == 4)
 62 leftOffsetj += 5;
 63 var container = document.createElement("div");
 64 var shifter = document.createElement("div");
 65 container.setAttribute('class', 'container');
 66 shifter.setAttribute('class', 'shifter8x8');
 67 container.style.left = (leftOffsetj + j * 20 + i * leftFraction) + "px"
 68 container.style.top = (topOffset + i * 20 + i * topFraction) + "px"
 69 shifter.style.left = (5 + j * leftFraction) + "px"
 70 shifter.style.top = (5 + j * topFraction) + "px"
 71 container.appendChild(shifter);
 72 test.appendChild(container);
 73 }
 74 }
 75 }
 76
 77 function setupTest()
 78 {
 79 // Vertical shifts:
 80 setupGrid10x10(10, 10, 0, 0.1)
 81 // Horizontal shifts:
 82 setupGrid10x10(200, 10, 0.1, 0);
 83
 84 // And in 8x8 (where exactly 0.5 is more common)
 85 setupGrid8x8(10, 200, 0, 0.125);
 86 setupGrid8x8(200, 200, 0.125, 0);
 87 }
 88
 89 setupTest();
 90</script>
 91</body>
 92</html>

LayoutTests/fast/sub-pixel/sub-pixel-composited-layers.html

 1<html>
 2<head>
 3<style>
 4 #test {
 5 margin: 5px;
 6 }
 7 #test.composite > .container {
 8 -webkit-transform: translateZ(0);
 9 opacity: 0.95;
 10 }
 11 .container {
 12 position: absolute;
 13 }
 14 .shifter {
 15 position: absolute;
 16 background-color: black;
 17 width: 12.5px;
 18 height: 12.5px;
 19 }
 20 .shifter8x8 {
 21 position: absolute;
 22 background-color: black;
 23 width: 16.5px;
 24 height: 16.5px;
 25 }
 26</style>
 27</head>
 28<body>
 29<div id=test class=composite>
 30</div>
 31<script>
 32 function setupGrid10x10(leftOffset, topOffset, leftFraction, topFraction)
 33 {
 34 var test = document.getElementById('test');
 35 for (var i = 0; i < 10; i++) {
 36 if (i == 5)
 37 topOffset += 5;
 38 var leftOffsetj = leftOffset;
 39 for (var j = 0; j < 10; j++) {
 40 if (j == 5)
 41 leftOffsetj += 5;
 42 var container = document.createElement("div");
 43 var shifter = document.createElement("div");
 44 container.setAttribute('class', 'container');
 45 shifter.setAttribute('class', 'shifter');
 46 container.style.left = (leftOffsetj + j * 16 + i * leftFraction) + "px"
 47 container.style.top = (topOffset + i * 16 + i * topFraction) + "px"
 48 shifter.style.left = (5 + j * leftFraction) + "px"
 49 shifter.style.top = (5 + j * topFraction) + "px"
 50 container.appendChild(shifter);
 51 test.appendChild(container);
 52 }
 53 }
 54 }
 55
 56 function setupGrid8x8(leftOffset, topOffset, leftFraction, topFraction)
 57 {
 58 var test = document.getElementById('test');
 59 for (var i = 0; i < 8; i++) {
 60 if (i == 4)
 61 topOffset += 5;
 62 var leftOffsetj = leftOffset;
 63 for (var j = 0; j < 8; j++) {
 64 if (j == 4)
 65 leftOffsetj += 5;
 66 var container = document.createElement("div");
 67 var shifter = document.createElement("div");
 68 container.setAttribute('class', 'container');
 69 shifter.setAttribute('class', 'shifter8x8');
 70 container.style.left = (leftOffsetj + j * 20 + i * leftFraction) + "px"
 71 container.style.top = (topOffset + i * 20 + i * topFraction) + "px"
 72 shifter.style.left = (5 + j * leftFraction) + "px"
 73 shifter.style.top = (5 + j * topFraction) + "px"
 74 container.appendChild(shifter);
 75 test.appendChild(container);
 76 }
 77 }
 78 }
 79
 80 function setupTest()
 81 {
 82 // Vertical shifts:
 83 setupGrid10x10(10, 10, 0, 0.1)
 84 // Horizontal shifts:
 85 setupGrid10x10(200, 10, 0.1, 0);
 86
 87 // And in 8x8 (where exactly 0.5 is more common)
 88 setupGrid8x8(10, 200, 0, 0.125);
 89 setupGrid8x8(200, 200, 0.125, 0);
 90 }
 91
 92 setupTest();
 93</script>
 94</body>
 95</html>