Bug 563878. Part 10. Overhaul generic parts of view/ to handle non-constant zoom view manager hierarchies. r=mats

This commit is contained in:
Timothy Nikkel 2010-07-18 21:23:47 -05:00
Родитель 83821cb794
Коммит a1c1ee7f41
4 изменённых файлов: 202 добавлений и 71 удалений

Просмотреть файл

@ -63,8 +63,8 @@ enum nsViewVisibility {
// IID for the nsIView interface
#define NS_IVIEW_IID \
{ 0xdb512cfa, 0xe00c, 0x4eff, \
{ 0xa2, 0x9c, 0x18, 0x74, 0x96, 0x63, 0x17, 0x69 } }
{ 0xfb9900df, 0x5956, 0x4175, \
{ 0x83, 0xba, 0x05, 0x74, 0x31, 0x96, 0x61, 0xee } }
// Public view flags are defined in this file
#define NS_VIEW_FLAGS_PUBLIC 0x00FF
@ -144,7 +144,8 @@ public:
/**
* Called to get the position of a view.
* The specified coordinates are in the parent view's coordinate space.
* The specified coordinates are relative to the parent view's origin, but
* are in appunits of this.
* This is the (0, 0) origin of the coordinate space established by this view.
* @param x out parameter for x position
* @param y out parameter for y position
@ -165,7 +166,8 @@ public:
/**
* Called to get the dimensions and position of the view's bounds.
* The view's bounds (x,y) are in the coordinate space of the parent view.
* The view's bounds (x,y) are relative to the origin of the parent view, but
* are in appunits of this.
* The view's bounds (x,y) might not be the same as the view's position,
* if the view has content above or to the left of its origin.
* @param aBounds out parameter for bounds
@ -177,6 +179,11 @@ public:
* Adding the return value to a point in the coordinate system of |this|
* will transform the point to the coordinate system of aOther.
*
* The offset is expressed in appunits of |this|. So if you are getting the
* offset between views in different documents that might have different
* appunits per devpixel ratios you need to be careful how you use the
* result.
*
* If aOther is null, this will return the offset of |this| from the
* root of the viewmanager tree.
*
@ -187,6 +194,15 @@ public:
*/
nsPoint GetOffsetTo(const nsIView* aOther) const;
/**
* Get the offset between the origin of |this| and the origin of aWidget.
* Adding the return value to a point in the coordinate system of |this|
* will transform the point to the coordinate system of aWidget.
*
* The offset is expressed in appunits of |this|.
*/
nsPoint GetOffsetToWidget(nsIWidget* aWidget) const;
/**
* Called to query the visibility state of a view.
* @result current visibility state
@ -250,7 +266,7 @@ public:
* Get the nearest widget in this view or a parent of this view and
* the offset from the widget's origin to this view's origin
* @param aOffset the offset from this view's origin to the widget's origin
* (usually positive)
* (usually positive) expressed in appunits of this.
* @return the widget closest to this view; can be null because some view trees
* don't have widgets at all (e.g., printing), but if any view in the view tree
* has a widget, then it's safe to assume this will not return null
@ -354,7 +370,8 @@ public:
// This is an app unit offset to add when converting view coordinates to
// widget coordinates. It is the offset in view coordinates from widget
// top-left to view top-left.
// origin (unlike views, widgets can't extend above or to the left of their
// origin) to view origin expressed in appunits of this.
nsPoint ViewToWidgetOffset() const { return mViewToWidgetOffset; }
protected:
@ -367,8 +384,11 @@ protected:
void *mClientData;
PRInt32 mZIndex;
nsViewVisibility mVis;
// position relative our parent view origin but in our appunits
nscoord mPosX, mPosY;
nsRect mDimBounds; // relative to parent
// relative to parent, but in our appunits
nsRect mDimBounds;
// in our appunits
nsPoint mViewToWidgetOffset;
float mOpacity;
PRUint32 mVFlags;

Просмотреть файл

@ -390,16 +390,14 @@ PRBool nsIView::IsEffectivelyVisible()
nsIntRect nsIView::CalcWidgetBounds(nsWindowType aType)
{
nsCOMPtr<nsIDeviceContext> dx;
mViewManager->GetDeviceContext(*getter_AddRefs(dx));
NS_ASSERTION(dx, "View manager can't be created without a device context");
PRInt32 p2a = dx->AppUnitsPerDevPixel();
PRInt32 p2a = mViewManager->AppUnitsPerDevPixel();
nsRect viewBounds(mDimBounds);
if (GetParent()) {
nsView* parent = static_cast<nsView*>(GetParent());
if (parent) {
nsPoint offset;
nsIWidget* parentWidget = GetParent()->GetNearestWidget(&offset);
nsIWidget* parentWidget = parent->GetNearestWidget(&offset, p2a);
// make viewBounds be relative to the parent widget, in appunits
viewBounds += offset;
@ -415,8 +413,8 @@ nsIntRect nsIView::CalcWidgetBounds(nsWindowType aType)
// Compute widget bounds in device pixels
nsIntRect newBounds = viewBounds.ToNearestPixels(p2a);
// Compute where the top-left of the widget ended up relative to the
// parent widget, in appunits
// Compute where the top-left of our widget ended up relative to the parent
// widget, in appunits.
nsPoint roundedOffset(NSIntPixelsToAppUnits(newBounds.x, p2a),
NSIntPixelsToAppUnits(newBounds.y, p2a));
@ -879,10 +877,7 @@ void nsIView::List(FILE* out, PRInt32 aIndent) const
for (i = aIndent; --i >= 0; ) fputs(" ", out);
fprintf(out, "%p ", (void*)this);
if (nsnull != mWindow) {
nsIDeviceContext *dx;
mViewManager->GetDeviceContext(dx);
nscoord p2a = dx->AppUnitsPerDevPixel();
NS_RELEASE(dx);
nscoord p2a = mViewManager->AppUnitsPerDevPixel();
nsIntRect rect;
mWindow->GetClientBounds(rect);
nsRect windowBounds = rect.ToAppUnits(p2a);
@ -913,50 +908,130 @@ void nsIView::List(FILE* out, PRInt32 aIndent) const
nsPoint nsIView::GetOffsetTo(const nsIView* aOther) const
{
const nsView* view = static_cast<const nsView*>(this);
return view->GetOffsetTo(static_cast<const nsView*>(aOther),
view->GetViewManager()->AppUnitsPerDevPixel());
}
nsPoint nsView::GetOffsetTo(const nsView* aOther) const
{
return GetOffsetTo(aOther, GetViewManager()->AppUnitsPerDevPixel());
}
nsPoint nsView::GetOffsetTo(const nsView* aOther, const PRInt32 aAPD) const
{
// We accumulate the final result in offset
nsPoint offset(0, 0);
const nsIView* v;
for (v = this; v != aOther && v; v = v->GetParent()) {
offset += v->GetPosition();
// The offset currently accumulated at the current APD
nsPoint docOffset(0, 0);
const nsView* v = this;
nsViewManager* currVM = v->GetViewManager();
PRInt32 currAPD = currVM->AppUnitsPerDevPixel();
const nsView* root = nsnull;
for ( ; v != aOther && v; root = v, v = v->GetParent()) {
nsViewManager* newVM = v->GetViewManager();
if (newVM != currVM) {
PRInt32 newAPD = newVM->AppUnitsPerDevPixel();
if (newAPD != currAPD) {
offset += docOffset.ConvertAppUnits(currAPD, aAPD);
docOffset.x = docOffset.y = 0;
currAPD = newAPD;
}
currVM = newVM;
}
docOffset += v->GetPosition();
}
offset += docOffset.ConvertAppUnits(currAPD, aAPD);
if (v != aOther) {
// Looks like aOther wasn't an ancestor of |this|. So now we have
// the root-VM-relative position of |this| in |offset|. Convert back
// to the coordinates of aOther
while (aOther) {
offset -= aOther->GetPosition();
aOther = aOther->GetParent();
}
// the root-VM-relative position of |this| in |offset|. Get the
// root-VM-relative position of aOther and subtract it.
nsPoint negOffset = aOther->GetOffsetTo(root, aAPD);
offset -= negOffset;
}
return offset;
}
nsPoint nsIView::GetOffsetToWidget(nsIWidget* aWidget) const
{
nsPoint pt;
// Get the view for widget
nsView* widgetView = static_cast<nsView*>(GetViewFor(aWidget));
if (!widgetView) {
return pt;
}
// Get the offset to the widget view in the widget view's APD
// We get the offset in the widget view's APD first and then convert to our
// APD afterwards so that we can include the widget view's ViewToWidgetOffset
// in the sum in its native APD, and then convert the whole thing to our APD
// so that we don't have to convert the APD of the relatively small
// ViewToWidgetOffset by itself with a potentially large relative rounding
// error.
pt = -widgetView->GetOffsetTo(static_cast<const nsView*>(this));
// Add in the offset to the widget.
pt += widgetView->ViewToWidgetOffset();
// Convert to our appunits.
PRInt32 widgetAPD = widgetView->GetViewManager()->AppUnitsPerDevPixel();
PRInt32 ourAPD = static_cast<const nsView*>(this)->
GetViewManager()->AppUnitsPerDevPixel();
pt = pt.ConvertAppUnits(widgetAPD, ourAPD);
return pt;
}
nsIWidget* nsIView::GetNearestWidget(nsPoint* aOffset) const
{
const nsView* view = static_cast<const nsView*>(this);
return view->GetNearestWidget(aOffset,
view->GetViewManager()->AppUnitsPerDevPixel());
}
nsIWidget* nsView::GetNearestWidget(nsPoint* aOffset) const
{
return GetNearestWidget(aOffset, GetViewManager()->AppUnitsPerDevPixel());
}
nsIWidget* nsView::GetNearestWidget(nsPoint* aOffset, const PRInt32 aAPD) const
{
// aOffset is based on the view's position, which ignores any chrome on
// attached parent widgets.
// We accumulate the final result in pt
nsPoint pt(0, 0);
const nsView* v;
for (v = static_cast<const nsView*>(this);
v && !v->HasWidget(); v = v->GetParent()) {
pt += v->GetPosition();
// The offset currently accumulated at the current APD
nsPoint docPt(0,0);
const nsView* v = this;
nsViewManager* currVM = v->GetViewManager();
PRInt32 currAPD = currVM->AppUnitsPerDevPixel();
for ( ; v && !v->HasWidget(); v = v->GetParent()) {
nsViewManager* newVM = v->GetViewManager();
if (newVM != currVM) {
PRInt32 newAPD = newVM->AppUnitsPerDevPixel();
if (newAPD != currAPD) {
pt += docPt.ConvertAppUnits(currAPD, aAPD);
docPt.x = docPt.y = 0;
currAPD = newAPD;
}
currVM = newVM;
}
docPt += v->GetPosition();
}
if (!v) {
if (aOffset) {
pt += docPt.ConvertAppUnits(currAPD, aAPD);
*aOffset = pt;
}
return nsnull;
}
// pt is now the offset from v's origin to this view's origin. The widget's
// origin is the top left corner of v's bounds, which may not coincide with
// the view's origin.
// pt is now the offset from v's origin to this view's origin.
// We add the ViewToWidgetOffset to get the offset to the widget.
if (aOffset) {
nsRect vBounds = v->GetBounds();
*aOffset = pt + v->GetPosition() - nsPoint(vBounds.x, vBounds.y) +
v->ViewToWidgetOffset();
docPt += v->ViewToWidgetOffset();
pt += docPt.ConvertAppUnits(currAPD, aAPD);
*aOffset = pt;
}
return v->GetWidget();
}
@ -980,3 +1055,28 @@ nsIView::SetDeletionObserver(nsWeakView* aDeletionObserver)
}
mDeletionObserver = aDeletionObserver;
}
nsRect
nsView::GetBoundsInParentUnits() const
{
nsView* parent = GetParent();
nsViewManager* VM = GetViewManager();
if (this != VM->GetRootView() || !parent) {
return mDimBounds;
}
PRInt32 ourAPD = VM->AppUnitsPerDevPixel();
PRInt32 parentAPD = parent->GetViewManager()->AppUnitsPerDevPixel();
return mDimBounds.ConvertAppUnitsRoundOut(ourAPD, parentAPD);
}
nsPoint
nsView::ConvertFromParentCoords(nsPoint aPt) const
{
nsView* parent = GetParent();
if (parent) {
aPt = aPt.ConvertAppUnits(parent->GetViewManager()->AppUnitsPerDevPixel(),
GetViewManager()->AppUnitsPerDevPixel());
}
aPt -= GetPosition();
return aPt;
}

Просмотреть файл

@ -71,7 +71,8 @@ public:
/**
* Called to indicate that the dimensions of the view have been changed.
* The x and y coordinates may be < 0, indicating that the view extends above
* or to the left of its origin position.
* or to the left of its origin position. The term 'dimensions' indicates it
* is relative to this view.
*/
virtual void SetDimensions(const nsRect &aRect, PRBool aPaint = PR_TRUE,
PRBool aResizeWidget = PR_TRUE);
@ -128,6 +129,8 @@ public:
PRBool GetZIndexIsAuto() const { return (mVFlags & NS_VIEW_FLAG_AUTO_ZINDEX) != 0; }
// This is a better interface than GetDimensions(nsRect&) above
nsRect GetDimensions() const { nsRect r = mDimBounds; r.MoveBy(-mPosX, -mPosY); return r; }
// Same as GetBounds but converts to parent appunits if they are different.
nsRect GetBoundsInParentUnits() const;
// These are defined exactly the same in nsIView, but for now they have to be redeclared
// here because of stupid C++ method hiding rules
@ -156,14 +159,7 @@ public:
void SetTopMost(PRBool aTopMost) { aTopMost ? mVFlags |= NS_VIEW_FLAG_TOPMOST : mVFlags &= ~NS_VIEW_FLAG_TOPMOST; }
PRBool IsTopMost() { return((mVFlags & NS_VIEW_FLAG_TOPMOST) != 0); }
// Don't use this method when you want to adjust an nsPoint.
// Just write "pt += view->GetPosition();"
// When everything's converted to nsPoint, this can go away.
void ConvertToParentCoords(nscoord* aX, nscoord* aY) const { *aX += mPosX; *aY += mPosY; }
// Don't use this method when you want to adjust an nsPoint.
// Just write "pt -= view->GetPosition();"
// When everything's converted to nsPoint, this can go away.
void ConvertFromParentCoords(nscoord* aX, nscoord* aY) const { *aX -= mPosX; *aY -= mPosY; }
nsPoint ConvertFromParentCoords(nsPoint aPt) const;
void ResetWidgetBounds(PRBool aRecurse, PRBool aMoveOnly, PRBool aInvalidateChangedSize);
void SetPositionIgnoringChildWidgets(nscoord aX, nscoord aY);
nsresult LoadWidget(const nsCID &aClassIID);
@ -178,6 +174,11 @@ public:
virtual ~nsView();
nsPoint GetOffsetTo(const nsView* aOther) const;
nsIWidget* GetNearestWidget(nsPoint* aOffset) const;
nsPoint GetOffsetTo(const nsView* aOther, const PRInt32 aAPD) const;
nsIWidget* GetNearestWidget(nsPoint* aOffset, const PRInt32 aAPD) const;
protected:
// Do the actual work of ResetWidgetBounds, unconditionally. Don't
// call this method if we have no widget.

Просмотреть файл

@ -506,9 +506,8 @@ NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags)
// Mark the entire view as damaged
nsView* view = static_cast<nsView*>(aView);
nsRect bounds = view->GetBounds();
view->ConvertFromParentCoords(&bounds.x, &bounds.y);
return UpdateView(view, bounds, aUpdateFlags);
nsRect dims = view->GetDimensions();
return UpdateView(view, dims, aUpdateFlags);
}
static PRBool
@ -655,6 +654,9 @@ NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect, PRU
nsView* view = static_cast<nsView*>(aView);
NS_ASSERTION(view->GetViewManager() == this,
"UpdateView called on view we don't own");
nsRect damagedRect(aRect);
if (damagedRect.IsEmpty()) {
return NS_OK;
@ -666,6 +668,9 @@ NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect, PRU
// can overlap each other and be translucent. So we have to possibly
// invalidate our rect in each of the widgets we have lying about.
damagedRect.MoveBy(view->GetOffsetTo(displayRoot));
PRInt32 rootAPD = displayRootVM->AppUnitsPerDevPixel();
PRInt32 APD = AppUnitsPerDevPixel();
damagedRect = damagedRect.ConvertAppUnitsRoundOut(APD, rootAPD);
displayRootVM->UpdateWidgetArea(displayRoot, displayRoot->GetWidget(),
nsRegion(damagedRect), nsnull);
@ -701,7 +706,7 @@ void nsViewManager::UpdateViews(nsView *aView, PRUint32 aUpdateFlags)
// update all children as well.
nsView* childView = aView->GetFirstChild();
while (nsnull != childView) {
UpdateViews(childView, aUpdateFlags);
childView->GetViewManager()->UpdateViews(childView, aUpdateFlags);
childView = childView->GetNextSibling();
}
}
@ -1146,7 +1151,7 @@ NS_IMETHODIMP nsViewManager::InsertChild(nsIView *aParent, nsIView *aChild, nsIV
//and mark this area as dirty if the view is visible...
if (nsViewVisibility_kHide != child->GetVisibility())
UpdateView(child, NS_VMREFRESH_NO_SYNC);
child->GetViewManager()->UpdateView(child, NS_VMREFRESH_NO_SYNC);
}
return NS_OK;
}
@ -1166,11 +1171,12 @@ NS_IMETHODIMP nsViewManager::RemoveChild(nsIView *aChild)
nsView* parent = child->GetParent();
if (nsnull != parent)
{
UpdateView(child, NS_VMREFRESH_NO_SYNC);
parent->RemoveChild(child);
}
if (nsnull != parent) {
NS_ASSERTION(child->GetViewManager() == this ||
parent->GetViewManager() == this, "wrong view manager");
child->GetViewManager()->UpdateView(child, NS_VMREFRESH_NO_SYNC);
parent->RemoveChild(child);
}
return NS_OK;
}
@ -1178,8 +1184,9 @@ NS_IMETHODIMP nsViewManager::RemoveChild(nsIView *aChild)
NS_IMETHODIMP nsViewManager::MoveViewTo(nsIView *aView, nscoord aX, nscoord aY)
{
nsView* view = static_cast<nsView*>(aView);
NS_ASSERTION(view->GetViewManager() == this, "wrong view manager");
nsPoint oldPt = view->GetPosition();
nsRect oldArea = view->GetBounds();
nsRect oldBounds = view->GetBoundsInParentUnits();
view->SetPosition(aX, aY);
// only do damage control if the view is visible
@ -1187,8 +1194,12 @@ NS_IMETHODIMP nsViewManager::MoveViewTo(nsIView *aView, nscoord aX, nscoord aY)
if ((aX != oldPt.x) || (aY != oldPt.y)) {
if (view->GetVisibility() != nsViewVisibility_kHide) {
nsView* parentView = view->GetParent();
UpdateView(parentView, oldArea, NS_VMREFRESH_NO_SYNC);
UpdateView(parentView, view->GetBounds(), NS_VMREFRESH_NO_SYNC);
if (parentView) {
nsViewManager* parentVM = parentView->GetViewManager();
parentVM->UpdateView(parentView, oldBounds, NS_VMREFRESH_NO_SYNC);
parentVM->UpdateView(parentView, view->GetBoundsInParentUnits(),
NS_VMREFRESH_NO_SYNC);
}
}
}
return NS_OK;
@ -1227,6 +1238,7 @@ void nsViewManager::InvalidateRectDifference(nsView *aView, const nsRect& aRect,
NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, const nsRect &aRect, PRBool aRepaintExposedAreaOnly)
{
nsView* view = static_cast<nsView*>(aView);
NS_ASSERTION(view->GetViewManager() == this, "wrong view manager");
nsRect oldDimensions;
view->GetDimensions(oldDimensions);
@ -1240,21 +1252,16 @@ NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, const nsRect &aRect, PRB
if (view->GetVisibility() == nsViewVisibility_kHide) {
view->SetDimensions(aRect, PR_FALSE);
} else {
nsRect oldBounds = view->GetBoundsInParentUnits();
view->SetDimensions(aRect, PR_TRUE);
if (!aRepaintExposedAreaOnly) {
//Invalidate the union of the old and new size
view->SetDimensions(aRect, PR_TRUE);
UpdateView(view, aRect, NS_VMREFRESH_NO_SYNC);
view->ConvertToParentCoords(&oldDimensions.x, &oldDimensions.y);
UpdateView(parentView, oldDimensions, NS_VMREFRESH_NO_SYNC);
UpdateView(parentView, oldBounds, NS_VMREFRESH_NO_SYNC);
} else {
view->SetDimensions(aRect, PR_TRUE);
InvalidateRectDifference(view, aRect, oldDimensions, NS_VMREFRESH_NO_SYNC);
nsRect r = aRect;
view->ConvertToParentCoords(&r.x, &r.y);
view->ConvertToParentCoords(&oldDimensions.x, &oldDimensions.y);
InvalidateRectDifference(parentView, oldDimensions, r, NS_VMREFRESH_NO_SYNC);
nsRect newBounds = view->GetBoundsInParentUnits();
InvalidateRectDifference(parentView, oldBounds, newBounds, NS_VMREFRESH_NO_SYNC);
}
}
}
@ -1282,6 +1289,7 @@ NS_IMETHODIMP nsViewManager::SetViewFloating(nsIView *aView, PRBool aFloating)
NS_IMETHODIMP nsViewManager::SetViewVisibility(nsIView *aView, nsViewVisibility aVisible)
{
nsView* view = static_cast<nsView*>(aView);
NS_ASSERTION(view->GetViewManager() == this, "wrong view manager");
if (aVisible != view->GetVisibility()) {
view->SetVisibility(aVisible);
@ -1291,7 +1299,9 @@ NS_IMETHODIMP nsViewManager::SetViewVisibility(nsIView *aView, nsViewVisibility
if (nsViewVisibility_kHide == aVisible) {
nsView* parentView = view->GetParent();
if (parentView) {
UpdateView(parentView, view->GetBounds(), NS_VMREFRESH_NO_SYNC);
parentView->GetViewManager()->
UpdateView(parentView, view->GetBoundsInParentUnits(),
NS_VMREFRESH_NO_SYNC);
}
}
else {