Bug 380438: Black lines appearing on the Opera Desktop Team Blog comments. r+sr=roc
--- a/gfx/public/nsRect.h
+++ b/gfx/public/nsRect.h
@@ -154,18 +154,25 @@ struct NS_GFX nsRect {
nsRect& operator-=(const nsPoint& aPoint) {x -= aPoint.x; y -= aPoint.y; return *this;}
nsRect& operator*=(const float aScale) {x = NSToCoordRound(x * aScale);
y = NSToCoordRound(y * aScale);
width = NSToCoordRound(width * aScale);
height = NSToCoordRound(height * aScale);
return *this;}
- nsRect& ScaleRoundOut(const float aScale);
- nsRect& ScaleRoundIn(const float aScale);
+ // Scale by aScale, converting coordinates to integers so that the result
+ // is the smallest integer-coordinate rectangle containing the unrounded result
+ nsRect& ScaleRoundOut(float aScale);
+ // Scale by aScale, converting coordinates to integers so that the result
+ // is the larges integer-coordinate rectangle contained in the unrounded result
+ nsRect& ScaleRoundIn(float aScale);
+ // Scale by aScale, converting coordinates to integers so that the result
+ // contains the same pixel centers as the unrounded result
+ nsRect& ScaleRoundPreservingCenters(float aScale);
// Helpers for accessing the vertices
nsPoint TopLeft() const { return nsPoint(x, y); }
nsPoint TopRight() const { return nsPoint(XMost(), y); }
nsPoint BottomLeft() const { return nsPoint(x, YMost()); }
nsPoint BottomRight() const { return nsPoint(XMost(), YMost()); }
nsSize Size() const { return nsSize(width, height); }
--- a/gfx/src/nsRect.cpp
+++ b/gfx/src/nsRect.cpp
@@ -176,39 +176,50 @@ void nsRect::Deflate(const nsMargin &aMa
{
x += aMargin.left;
y += aMargin.top;
width -= aMargin.left + aMargin.right;
height -= aMargin.top + aMargin.bottom;
}
// scale the rect but round to smallest containing rect
-nsRect& nsRect::ScaleRoundOut(const float aScale)
+nsRect& nsRect::ScaleRoundOut(float aScale)
{
- nscoord right = NSToCoordCeil(float(x + width) * aScale);
- nscoord bottom = NSToCoordCeil(float(y + height) * aScale);
+ nscoord right = NSToCoordCeil(float(XMost()) * aScale);
+ nscoord bottom = NSToCoordCeil(float(YMost()) * aScale);
x = NSToCoordFloor(float(x) * aScale);
y = NSToCoordFloor(float(y) * aScale);
width = (right - x);
height = (bottom - y);
return *this;
}
// scale the rect but round to largest contained rect
-nsRect& nsRect::ScaleRoundIn(const float aScale)
+nsRect& nsRect::ScaleRoundIn(float aScale)
{
- nscoord right = NSToCoordFloor(float(x + width) * aScale);
- nscoord bottom = NSToCoordFloor(float(y + height) * aScale);
+ nscoord right = NSToCoordFloor(float(XMost()) * aScale);
+ nscoord bottom = NSToCoordFloor(float(YMost()) * aScale);
x = NSToCoordCeil(float(x) * aScale);
y = NSToCoordCeil(float(y) * aScale);
width = (right - x);
height = (bottom - y);
return *this;
}
+nsRect& nsRect::ScaleRoundPreservingCenters(float aScale)
+{
+ nscoord right = NSToCoordRound(float(XMost()) * aScale);
+ nscoord bottom = NSToCoordRound(float(YMost()) * aScale);
+ x = NSToCoordRound(float(x) * aScale);
+ y = NSToCoordRound(float(y) * aScale);
+ width = (right - x);
+ height = (bottom - y);
+ return *this;
+}
+
#ifdef DEBUG
// Diagnostics
FILE* operator<<(FILE* out, const nsRect& rect)
{
nsAutoString tmp;
// Output the coordinates in fractional pixels so they're easier to read
--- a/view/src/nsView.cpp
+++ b/view/src/nsView.cpp
@@ -381,21 +381,21 @@ void nsView::DoResetWidgetBounds(PRBool
// put offset into screen coordinates
nsRect screenRect(0,0,1,1);
parentWidget->WidgetToScreen(screenRect, screenRect);
offset += nsPoint(NSIntPixelsToAppUnits(screenRect.x, p2a),
NSIntPixelsToAppUnits(screenRect.y, p2a));
}
}
- nsRect newBounds(NSAppUnitsToIntPixels((mDimBounds.x + offset.x), p2a),
- NSAppUnitsToIntPixels((mDimBounds.y + offset.y), p2a),
- NSAppUnitsToIntPixels(mDimBounds.width, p2a),
- NSAppUnitsToIntPixels(mDimBounds.height, p2a));
-
+ nsRect viewBounds(mDimBounds + offset);
+
+ nsRect newBounds(viewBounds);
+ newBounds.ScaleRoundPreservingCenters(1.0f / p2a);
+
PRBool changedPos = PR_TRUE;
PRBool changedSize = PR_TRUE;
if (!(mVFlags & NS_VIEW_FLAG_HAS_POSITIONED_WIDGET)) {
mVFlags |= NS_VIEW_FLAG_HAS_POSITIONED_WIDGET;
} else {
changedPos = curBounds.TopLeft() != newBounds.TopLeft();
changedSize = curBounds.Size() != newBounds.Size();
}
@@ -407,16 +407,20 @@ void nsView::DoResetWidgetBounds(PRBool
} else {
mWindow->Move(newBounds.x, newBounds.y);
}
} else {
if (changedSize && !aMoveOnly) {
mWindow->Resize(newBounds.width, newBounds.height, aInvalidateChangedSize);
} // else do nothing!
}
+
+ nsPoint roundedOffset(NSIntPixelsToAppUnits(newBounds.x, p2a),
+ NSIntPixelsToAppUnits(newBounds.y, p2a));
+ mViewToWidgetOffset = viewBounds.TopLeft() - roundedOffset;
}
void nsView::SetDimensions(const nsRect& aRect, PRBool aPaint, PRBool aResizeWidget)
{
nsRect dims = aRect;
dims.MoveBy(mPosX, mPosY);
// Don't use nsRect's operator== here, since it returns true when
@@ -853,17 +857,18 @@ nsIWidget* nsIView::GetNearestWidget(nsP
return NS_STATIC_CAST(const nsView*, this)->GetViewManager()->GetWidget();
}
// pt is now the offset from v's origin to this's origin
// The widget's origin is the top left corner of v's bounds, which may
// not coincide with v's origin
if (aOffset) {
nsRect vBounds = v->GetBounds();
- *aOffset = pt + v->GetPosition() - nsPoint(vBounds.x, vBounds.y);
+ *aOffset = pt + v->GetPosition() - nsPoint(vBounds.x, vBounds.y) -
+ v->ViewToWidgetOffset();
}
return v->GetWidget();
}
PRBool nsIView::IsRoot() const
{
NS_ASSERTION(mViewManager != nsnull," View manager is null in nsView::IsRoot()");
return mViewManager->GetRootView() == this;
--- a/view/src/nsView.h
+++ b/view/src/nsView.h
@@ -213,22 +213,27 @@ public:
// Update the cached RootViewManager for all view manager descendents,
// If the hierarchy is being removed, aViewManagerParent points to the view
// manager for the hierarchy's old parent, and will have its mouse grab
// released if it points to any view in this view hierarchy.
void InvalidateHierarchy(nsViewManager *aViewManagerParent);
virtual ~nsView();
+ nsPoint ViewToWidgetOffset() const {
+ return mViewToWidgetOffset;
+ }
+
protected:
// Do the actual work of ResetWidgetBounds, unconditionally. Don't
// call this method if we have no widget.
void DoResetWidgetBounds(PRBool aMoveOnly, PRBool aInvalidateChangedSize);
nsZPlaceholderView* mZParent;
// mClipRect is relative to the view's origin.
nsRect* mClipRect;
nsRegion* mDirtyRegion;
+ nsPoint mViewToWidgetOffset;
PRPackedBool mChildRemoved;
};
#endif
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -478,18 +478,23 @@ void nsViewManager::Refresh(nsView *aVie
nsRect damageRect = damageRegion.GetBounds();
PRInt32 p2a = mContext->AppUnitsPerDevPixel();
nsRefPtr<gfxContext> ctx =
(gfxContext*) localcx->GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
ctx->Save();
- ctx->Translate(gfxPoint(NSAppUnitsToIntPixels(viewRect.x, p2a),
- NSAppUnitsToIntPixels(viewRect.y, p2a)));
+ nsPoint vtowoffset = aView->ViewToWidgetOffset();
+ ctx->Translate(gfxPoint(gfxFloat(vtowoffset.x) / p2a,
+ gfxFloat(vtowoffset.y) / p2a));
+
+ NS_ASSERTION(!viewRect.x && !viewRect.y, "When exactly is this supposed to be non-zero?");
+ ctx->Translate(gfxPoint(gfxFloat(viewRect.x) / p2a,
+ gfxFloat(viewRect.y) / p2a));
nsRegion opaqueRegion;
AddCoveringWidgetsToOpaqueRegion(opaqueRegion, mContext, aView);
damageRegion.Sub(damageRegion, opaqueRegion);
RenderViews(aView, *localcx, damageRegion);
ctx->Restore();