Fixing bug 81290. The element.offsetXXX properties contained incorrect values when the element is positioned, or a child of a positioned element, this made these properties kinda useless since we were nowhere close to IE wrt the values of these properties. r=pollmann@netscape.com, sr=vidur@netscape.com

This commit is contained in:
jst%netscape.com 2001-06-29 22:44:20 +00:00
Родитель c47e29468b
Коммит b0304d8e85
1 изменённых файлов: 188 добавлений и 92 удалений

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

@ -29,7 +29,7 @@
#include "nsICSSDeclaration.h" #include "nsICSSDeclaration.h"
#include "nsIDocument.h" #include "nsIDocument.h"
#include "nsIDocumentEncoder.h" #include "nsIDocumentEncoder.h"
#include "nsIDOMDocumentFragment.h" #include "nsIDOMHTMLDocument.h"
#include "nsIDOMAttr.h" #include "nsIDOMAttr.h"
#include "nsIDOMEventReceiver.h" #include "nsIDOMEventReceiver.h"
#include "nsIDOMNamedNodeMap.h" #include "nsIDOMNamedNodeMap.h"
@ -413,7 +413,7 @@ class nsGenericHTMLElementTearoff : public nsIDOMNSHTMLElement,
NS_ADDREF(mElement); NS_ADDREF(mElement);
} }
~nsGenericHTMLElementTearoff() virtual ~nsGenericHTMLElementTearoff()
{ {
NS_RELEASE(mElement); NS_RELEASE(mElement);
} }
@ -732,121 +732,217 @@ nsGenericHTMLElement::GetOffsetRect(nsRect& aRect,
nsIAtom* aOffsetParentTag, nsIAtom* aOffsetParentTag,
nsIContent** aOffsetParent) nsIContent** aOffsetParent)
{ {
nsresult res = NS_OK;
*aOffsetParent = nsnull; *aOffsetParent = nsnull;
aRect.x = aRect.y = 0; aRect.x = aRect.y = 0;
aRect.Empty(); aRect.Empty();
if(mDocument) { if (!mDocument) {
// Get Presentation shell 0 return NS_OK;
nsCOMPtr<nsIPresShell> presShell; }
mDocument->GetShellAt(0, getter_AddRefs(presShell));
if(presShell) { // Get Presentation shell 0
// Flush all pending notifications so that our frames are uptodate nsCOMPtr<nsIPresShell> presShell;
mDocument->FlushPendingNotifications(); mDocument->GetShellAt(0, getter_AddRefs(presShell));
// Get the Frame for our content if (!presShell) {
nsIFrame* frame = nsnull; return NS_OK;
presShell->GetPrimaryFrameFor(this, &frame); }
if(frame != nsnull) {
// Get it's origin
nsPoint origin;
frame->GetOrigin(origin);
// Get the union of all rectangles in this and continuation frames // Get the Presentation Context from the Shell
nsRect rcFrame; nsCOMPtr<nsIPresContext> context;
nsIFrame* next = frame; presShell->GetPresContext(getter_AddRefs(context));
do {
nsRect rect; if (!context) {
next->GetRect(rect); return NS_OK;
rcFrame.UnionRect(rcFrame, rect); }
next->GetNextInFlow(&next);
} while (nsnull != next); // Flush all pending notifications so that our frames are uptodate
mDocument->FlushPendingNotifications();
// Get the Frame for our content
nsIFrame* frame = nsnull;
presShell->GetPrimaryFrameFor(this, &frame);
if (!frame) {
return NS_OK;
}
// Get the union of all rectangles in this and continuation frames
nsRect rcFrame;
nsIFrame* next = frame;
do {
nsRect rect;
next->GetRect(rect);
rcFrame.UnionRect(rcFrame, rect);
next->GetNextInFlow(&next);
} while (next);
// Find the frame parent whose content's tagName either matches nsCOMPtr<nsIContent> docElement;
// the tagName passed in or is the document element. mDocument->GetRootContent(getter_AddRefs(docElement));
nsCOMPtr<nsIContent> docElement;
mDocument->GetRootContent(getter_AddRefs(docElement));
nsIFrame* parent = frame;
nsCOMPtr<nsIContent> parentContent;
frame->GetParent(&parent);
while (parent) {
parent->GetContent(getter_AddRefs(parentContent));
if (parentContent) {
// If we've hit the document element, break here
if (parentContent.get() == docElement.get()) {
break;
}
nsCOMPtr<nsIAtom> tag;
// If the tag of this frame matches the one passed in, break here
parentContent->GetTag(*getter_AddRefs(tag));
if (tag.get() == aOffsetParentTag) {
*aOffsetParent = parentContent;
NS_IF_ADDREF(*aOffsetParent);
break; // Find the frame parent whose content's tagName either matches
} // the tagName passed in or is the document element.
} nsCOMPtr<nsIContent> content;
// Add the parent's origin to our own to get to the nsIFrame* parent = nsnull;
// right coordinate system PRBool done = PR_FALSE;
nsPoint parentOrigin; nsCOMPtr<nsIAtom> tag;
parent->GetOrigin(parentOrigin);
origin += parentOrigin;
parent->GetParent(&parent);
frame->GetContent(getter_AddRefs(content));
if (content) {
content->GetTag(*getter_AddRefs(tag));
if (tag.get() == aOffsetParentTag || content == docElement) {
done = PR_TRUE;
parent = frame;
}
}
const nsStyleDisplay* display = nsnull;
nsPoint origin(0, 0);
if (!done) {
PRBool is_absolutely_positioned = PR_FALSE;
frame->GetOrigin(origin);
frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display);
if (display && display->IsAbsolutelyPositioned()) {
// If the primary frame or a parent is absolutely positioned
// (fixed or absolute) we stop walking up the frame parent
// chain
is_absolutely_positioned = PR_TRUE;
}
frame->GetParent(&parent);
while (parent) {
parent->GetStyleData(eStyleStruct_Display,
(const nsStyleStruct*&)display);
if (display) {
if (display->IsPositioned()) {
// Stop at the first *parent* that is positioned (fixed,
// absolute, or relatiive)
parent->GetContent(aOffsetParent);
break;
}
}
// Add the parent's origin to our own to get to the
// right coordinate system
if (!is_absolutely_positioned) {
nsPoint parentOrigin;
parent->GetOrigin(parentOrigin);
origin += parentOrigin;
}
parent->GetContent(getter_AddRefs(content));
if (content) {
// If we've hit the document element, break here
if (content == docElement) {
break;
} }
// For the origin, add in the border for the frame content->GetTag(*getter_AddRefs(tag));
const nsStyleBorder* border;
nsStyleCoord coord; // If the tag of this frame matches the one passed in, break here
frame->GetStyleData(eStyleStruct_Border, (const nsStyleStruct*&)border); if (tag.get() == aOffsetParentTag) {
if (border) { if (parent != frame) {
if (eStyleUnit_Coord == border->mBorder.GetLeftUnit()) { *aOffsetParent = content;
origin.x += border->mBorder.GetLeft(coord).GetCoordValue(); NS_ADDREF(*aOffsetParent);
}
if (eStyleUnit_Coord == border->mBorder.GetTopUnit()) {
origin.y += border->mBorder.GetTop(coord).GetCoordValue();
} }
break;
} }
}
// And subtract out the border for the parent parent->GetParent(&parent);
if (parent) { }
const nsStyleBorder* parentBorder;
parent->GetStyleData(eStyleStruct_Border, (const nsStyleStruct*&)parentBorder);
if (parentBorder) {
if (eStyleUnit_Coord == parentBorder->mBorder.GetLeftUnit()) {
origin.x -= parentBorder->mBorder.GetLeft(coord).GetCoordValue();
}
if (eStyleUnit_Coord == parentBorder->mBorder.GetTopUnit()) {
origin.y -= parentBorder->mBorder.GetTop(coord).GetCoordValue();
}
}
}
// Get the Presentation Context from the Shell if (is_absolutely_positioned && !*aOffsetParent) {
nsCOMPtr<nsIPresContext> context; // If this element is absolutely positioned, but we don't have
presShell->GetPresContext(getter_AddRefs(context)); // an offset parent it means this element is an absolutely
// positioned child that's not nested inside another positioned
// element, in this case the element's frame's parent is the
// frame for the HTML element so we fail to find the body in the
// parent chain. We want the offset parent in this case to be
// the body, so we just get the body element from the document.
if(context) { nsCOMPtr<nsIDOMHTMLDocument> html_doc(do_QueryInterface(mDocument));
// Get the scale from that Presentation Context
float scale;
context->GetTwipsToPixels(&scale);
// Convert to pixels using that scale if (html_doc) {
aRect.x = NSTwipsToIntPixels(origin.x, scale); nsCOMPtr<nsIDOMHTMLElement> html_element;
aRect.y = NSTwipsToIntPixels(origin.y, scale);
aRect.width = NSTwipsToIntPixels(rcFrame.width, scale); html_doc->GetBody(getter_AddRefs(html_element));
aRect.height = NSTwipsToIntPixels(rcFrame.height, scale);
if (html_element) {
CallQueryInterface(html_element, aOffsetParent);
} }
} }
} }
} }
return res; // For the origin, add in the border for the frame
const nsStyleBorder* border = nsnull;
nsStyleCoord coord;
#if 0
// We used to do this to include the border of the frame in the
// calculations, but I think that's wrong. My tests show that we
// work more like IE if we don't do this, so lets try this and see
// if people agree.
frame->GetStyleData(eStyleStruct_Border, (const nsStyleStruct*&)border);
if (border) {
if (eStyleUnit_Coord == border->mBorder.GetLeftUnit()) {
origin.x += border->mBorder.GetLeft(coord).GetCoordValue();
}
if (eStyleUnit_Coord == border->mBorder.GetTopUnit()) {
origin.y += border->mBorder.GetTop(coord).GetCoordValue();
}
}
#endif
// And subtract out the border for the parent
if (parent) {
border = nsnull;
parent->GetStyleData(eStyleStruct_Border, (const nsStyleStruct*&)border);
if (border) {
if (eStyleUnit_Coord == border->mBorder.GetLeftUnit()) {
origin.x -= border->mBorder.GetLeft(coord).GetCoordValue();
}
if (eStyleUnit_Coord == border->mBorder.GetTopUnit()) {
origin.y -= border->mBorder.GetTop(coord).GetCoordValue();
}
}
}
// Get the scale from that Presentation Context
float scale;
context->GetTwipsToPixels(&scale);
// Convert to pixels using that scale
aRect.x = NSTwipsToIntPixels(origin.x, scale);
aRect.y = NSTwipsToIntPixels(origin.y, scale);
aRect.width = NSTwipsToIntPixels(rcFrame.width, scale);
aRect.height = NSTwipsToIntPixels(rcFrame.height, scale);
return NS_OK;
} }
nsresult nsresult