int Element::GetFrameOffset(long* x, long* y) { LOG(TRACE) << "Entering Element::GetFrameOffset"; CComPtr<IHTMLDocument2> owner_doc; int status_code = this->GetContainingDocument(true, &owner_doc); if (status_code != SUCCESS) { LOG(WARN) << "Unable to get containing document"; return status_code; } CComPtr<IHTMLWindow2> owner_doc_window; HRESULT hr = owner_doc->get_parentWindow(&owner_doc_window); if (!owner_doc_window) { LOG(WARN) << "Unable to get parent window, call to IHTMLDocument2::get_parentWindow failed"; return ENOSUCHDOCUMENT; } CComPtr<IHTMLWindow2> parent_window; hr = owner_doc_window->get_parent(&parent_window); if (parent_window && !owner_doc_window.IsEqualObject(parent_window)) { CComPtr<IHTMLDocument2> parent_doc; status_code = this->GetParentDocument(parent_window, &parent_doc); CComPtr<IHTMLFramesCollection2> frames; hr = parent_doc->get_frames(&frames); long frame_count(0); hr = frames->get_length(&frame_count); CComVariant index; index.vt = VT_I4; for (long i = 0; i < frame_count; ++i) { // See if the document in each frame is this element's // owner document. index.lVal = i; CComVariant result; hr = frames->item(&index, &result); CComQIPtr<IHTMLWindow2> frame_window(result.pdispVal); if (!frame_window) { // Frame is not an HTML frame. continue; } CComPtr<IHTMLDocument2> frame_doc; hr = frame_window->get_document(&frame_doc); if (frame_doc.IsEqualObject(owner_doc)) { // The document in this frame *is* this element's owner // document. Get the frameElement property of the document's // containing window (which is itself an HTML element, either // a frame or an iframe). Then get the x and y coordinates of // that frame element. std::wstring script_source = L"(function(){ return function() { return arguments[0].frameElement };})();"; Script script_wrapper(frame_doc, script_source, 1); CComVariant window_variant(frame_window); script_wrapper.AddArgument(window_variant); script_wrapper.Execute(); CComQIPtr<IHTMLElement> frame_element(script_wrapper.result().pdispVal); // Wrap the element so we can find its location. Element element_wrapper(frame_element, this->containing_window_handle_); long frame_x, frame_y, frame_width, frame_height; status_code = element_wrapper.GetLocation(&frame_x, &frame_y, &frame_width, &frame_height); if (status_code == SUCCESS) { *x = frame_x; *y = frame_y; } break; } } } return SUCCESS; }
nsresult nsFrameLoader::EnsureDocShell() { if (mDocShell) { return NS_OK; } NS_ENSURE_STATE(!mDestroyCalled); // Get our parent docshell off the document of mOwnerContent // XXXbz this is such a total hack.... We really need to have a // better setup for doing this. nsIDocument* doc = mOwnerContent->GetDocument(); if (!doc) { return NS_ERROR_UNEXPECTED; } nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_GetInterface(doc->GetScriptGlobalObject()); // Create the docshell... mDocShell = do_CreateInstance("@mozilla.org/webshell;1"); NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); // Get the frame name and tell the docshell about it. nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell)); NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE); nsAutoString frameName; PRInt32 namespaceID = mOwnerContent->GetNameSpaceID(); if (namespaceID == kNameSpaceID_XHTML) { mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName); } else { mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName); // XXX if no NAME then use ID, after a transition period this will be // changed so that XUL only uses ID too (bug 254284). if (frameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) { mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName); } } if (!frameName.IsEmpty()) { docShellAsItem->SetName(frameName.get()); } // If our container is a web-shell, inform it that it has a new // child. If it's not a web-shell then some things will not operate // properly. nsCOMPtr<nsIDocShellTreeNode> parentAsNode(do_QueryInterface(parentAsWebNav)); if (parentAsNode) { // Note: This logic duplicates a lot of logic in // nsSubDocumentFrame::AttributeChanged. We should fix that. nsCOMPtr<nsIDocShellTreeItem> parentAsItem = do_QueryInterface(parentAsNode); PRInt32 parentType; parentAsItem->GetItemType(&parentType); nsAutoString value; PRBool isContent = PR_FALSE; if (mOwnerContent->IsNodeOfType(nsINode::eXUL)) { mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value); } // we accept "content" and "content-xxx" values. // at time of writing, we expect "xxx" to be "primary" or "targetable", but // someday it might be an integer expressing priority or something else. isContent = value.LowerCaseEqualsLiteral("content") || StringBeginsWith(value, NS_LITERAL_STRING("content-"), nsCaseInsensitiveStringComparator()); if (isContent) { // The web shell's type is content. docShellAsItem->SetItemType(nsIDocShellTreeItem::typeContent); } else { // Inherit our type from our parent webshell. If it is // chrome, we'll be chrome. If it is content, we'll be // content. docShellAsItem->SetItemType(parentType); } parentAsNode->AddChild(docShellAsItem); if (parentType == nsIDocShellTreeItem::typeChrome && isContent) { mIsTopLevelContent = PR_TRUE; // XXXbz why is this in content code, exactly? We should handle // this some other way..... Not sure how yet. nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner; parentAsItem->GetTreeOwner(getter_AddRefs(parentTreeOwner)); PRBool is_primary = value.LowerCaseEqualsLiteral("content-primary"); if (parentTreeOwner) { PRBool is_targetable = is_primary || value.LowerCaseEqualsLiteral("content-targetable"); parentTreeOwner->ContentShellAdded(docShellAsItem, is_primary, is_targetable, value); } } // Make sure all shells have links back to the content element // in the nearest enclosing chrome shell. nsCOMPtr<nsIDOMEventTarget> chromeEventHandler; if (parentType == nsIDocShellTreeItem::typeChrome) { // Our parent shell is a chrome shell. It is therefore our nearest // enclosing chrome shell. chromeEventHandler = do_QueryInterface(mOwnerContent); NS_ASSERTION(chromeEventHandler, "This mContent should implement this."); } else { nsCOMPtr<nsIDocShell> parentShell(do_QueryInterface(parentAsNode)); // Our parent shell is a content shell. Get the chrome event // handler from it and use that for our shell as well. parentShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler)); } mDocShell->SetChromeEventHandler(chromeEventHandler); } // This is nasty, this code (the do_GetInterface(mDocShell) below) // *must* come *after* the above call to // mDocShell->SetChromeEventHandler() for the global window to get // the right chrome event handler. // Tell the window about the frame that hosts it. nsCOMPtr<nsIDOMElement> frame_element(do_QueryInterface(mOwnerContent)); NS_ASSERTION(frame_element, "frame loader owner element not a DOM element!"); nsCOMPtr<nsPIDOMWindow> win_private(do_GetInterface(mDocShell)); NS_ENSURE_TRUE(win_private, NS_ERROR_UNEXPECTED); nsIDOMElement* oldFrame = win_private->GetFrameElementInternal(); win_private->SetFrameElementInternal(frame_element); NS_ADDREF(frame_element.get()); NS_IF_RELEASE(oldFrame); nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell)); NS_ENSURE_TRUE(base_win, NS_ERROR_UNEXPECTED); // This is kinda whacky, this call doesn't really create anything, // but it must be called to make sure things are properly // initialized base_win->Create(); return NS_OK; }