diff options
Diffstat (limited to 'embed/xulrunner/embed/EventContext.cpp')
-rw-r--r-- | embed/xulrunner/embed/EventContext.cpp | 1105 |
1 files changed, 1105 insertions, 0 deletions
diff --git a/embed/xulrunner/embed/EventContext.cpp b/embed/xulrunner/embed/EventContext.cpp new file mode 100644 index 000000000..6e22fce8a --- /dev/null +++ b/embed/xulrunner/embed/EventContext.cpp @@ -0,0 +1,1105 @@ +/* + * Copyright © 2000-2004 Marco Pesenti Gritti + * Copyright © 2003, 2004 Christian Persch + * Copyright © 2004 Crispin Flowerday + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <gdk/gdkkeysyms.h> + +#include <nsStringAPI.h> + +#include <nsComponentManagerUtils.h> +#include <nsIDOM3Node.h> +#include <nsIDOMAbstractView.h> +#include <nsIDOMCharacterData.h> +#include <nsIDOMCSSPrimitiveValue.h> +#include <nsIDOMCSSStyleDeclaration.h> +#include <nsIDOMDocument.h> +#include <nsIDOMDocumentView.h> +#include <nsIDOMElementCSSInlineStyle.h> +#include <nsIDOMElement.h> +#include <nsIDOMEvent.h> +#include <nsIDOMEventTarget.h> +#include <nsIDOMEventTarget.h> +#include <nsIDOMHTMLAnchorElement.h> +#include <nsIDOMHTMLAreaElement.h> +#include <nsIDOMHTMLBodyElement.h> +#include <nsIDOMHTMLButtonElement.h> +#include <nsIDOMHTMLEmbedElement.h> +#include <nsIDOMHTMLImageElement.h> +#include <nsIDOMHTMLInputElement.h> +#include <nsIDOMHTMLIsIndexElement.h> +#include <nsIDOMHTMLLabelElement.h> +#include <nsIDOMHTMLLegendElement.h> +#include <nsIDOMHTMLMapElement.h> +#include <nsIDOMHTMLObjectElement.h> +#include <nsIDOMHTMLSelectElement.h> +#include <nsIDOMHTMLTextAreaElement.h> +#include <nsIDOMKeyEvent.h> +#include <nsIDOMMouseEvent.h> +#include <nsIDOMNode.h> +#include <nsIDOMNodeList.h> +#include <nsIDOMNSHTMLDocument.h> +#include <nsIDOMNSUIEvent.h> +#include <nsIInterfaceRequestor.h> +#include <nsIInterfaceRequestorUtils.h> +#include <nsIServiceManager.h> +#include <nsIURI.h> + +#ifdef ALLOW_PRIVATE_API +#include <nsIDOMNSEvent.h> +#include <nsIDOMNSHTMLElement.h> +#include <nsIDOMViewCSS.h> +#include <nsIDOMViewCSS.h> +#include <nsIDOMXULDocument.h> +#include <nsITextToSubURI.h> +#endif + +#include "ephy-debug.h" + +#include "EphyBrowser.h" +#include "EphyUtils.h" + +#include "EventContext.h" + + +#define KEY_CODE 256 + +EventContext::EventContext () +{ + LOG ("EventContext ctor [%p]", this); +} + +EventContext::~EventContext () +{ + LOG ("EventContext dtor [%p]", this); +} + +nsresult EventContext::Init (EphyBrowser *browser) +{ + mBrowser = browser; + mDOMDocument = nsnull; + + return NS_OK; +} + +nsresult EventContext::GatherTextUnder (nsIDOMNode* aNode, nsAString& aResult) +{ + nsString text; + nsCOMPtr<nsIDOMNode> node; + aNode->GetFirstChild(getter_AddRefs(node)); + PRUint32 depth = 1; + + while (node && depth) + { + nsCOMPtr<nsIDOMCharacterData> charData(do_QueryInterface(node)); + PRUint16 nodeType; + + node->GetNodeType(&nodeType); + if (charData && nodeType == nsIDOMNode::TEXT_NODE) + { + /* Add this text to our collection. */ + text += ' '; + nsString data; + charData->GetData(data); + text += data; + } + else + { + nsCOMPtr<nsIDOMHTMLImageElement> img(do_QueryInterface(node)); + if (img) + { + nsString altText; + img->GetAlt(altText); + if (altText.Length()) + { + text = altText; + break; + } + } + } + + /* Find the next node to test. */ + PRBool hasChildNodes; + node->HasChildNodes(&hasChildNodes); + if (hasChildNodes) + { + nsCOMPtr<nsIDOMNode> temp = node; + temp->GetFirstChild(getter_AddRefs(node)); + depth++; + } + else + { + nsCOMPtr<nsIDOMNode> nextSibling; + node->GetNextSibling(getter_AddRefs(nextSibling)); + if (nextSibling) + { + node = nextSibling; + } + else + { + nsCOMPtr<nsIDOMNode> parentNode; + node->GetParentNode(getter_AddRefs(parentNode)); + if (!parentNode) + { + node = nsnull; + } + else + { + parentNode->GetNextSibling(getter_AddRefs(nextSibling)); + node = nextSibling; + depth--; + } + } + } + } + + /* FIXME we should trim spaces here */ + + aResult = text; + + return NS_OK; +} + +/* FIXME: we should resolve against the element's base, not the document's base */ +nsresult EventContext::ResolveBaseURL (const nsAString &relurl, nsACString &url) +{ + nsCString cRelURL; + NS_UTF16ToCString (relurl, NS_CSTRING_ENCODING_UTF8, cRelURL); + + return mBaseURI->Resolve (cRelURL, url); +} + +nsresult EventContext::Unescape (const nsACString &aEscaped, nsACString &aUnescaped) +{ + if (!aEscaped.Length()) return NS_ERROR_FAILURE; + + nsCOMPtr<nsITextToSubURI> escaper + (do_CreateInstance ("@mozilla.org/intl/texttosuburi;1")); + NS_ENSURE_TRUE (escaper, NS_ERROR_FAILURE); + + nsresult rv; + nsCString encoding; + rv = mBrowser->GetEncoding (encoding); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + nsString unescaped; + rv = escaper->UnEscapeURIForUI (encoding, aEscaped, unescaped); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && unescaped.Length(), NS_ERROR_FAILURE); + + NS_UTF16ToCString (unescaped, NS_CSTRING_ENCODING_UTF8, aUnescaped); + + return NS_OK; +} + +nsresult EventContext::GetEventContext (nsIDOMEventTarget *EventTarget, + MozillaEmbedEvent *info) +{ + nsresult rv; + + const PRUnichar hrefLiteral[] = {'h', 'r', 'e', 'f', '\0'}; + const PRUnichar imgLiteral[] = {'i', 'm', 'g', '\0'}; + const PRUnichar typeLiteral[] = {'t', 'y', 'p', 'e', '\0'}; + const PRUnichar xlinknsLiteral[] = {'h', 't', 't', 'p', ':', '/', '/','w', + 'w', 'w', '.', 'w', '3', '.', 'o', 'r', + 'g', '/', '1', '9', '9', '9', '/', 'x', + 'l', 'i', 'n', 'k', '\0'}; + const PRUnichar bodyLiteral[] = { 'b', 'o', 'd', 'y', '\0' }; + + mEmbedEvent = info; + + info->context = EPHY_EMBED_CONTEXT_DOCUMENT; + + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(EventTarget, &rv); + if (NS_FAILED(rv) || !node) return NS_ERROR_FAILURE; + + /* Is page xul ? then do not display context menus + * FIXME I guess there is an easier way ... */ + /* From philipl: This test needs to be here otherwise we + * arrogantly assume we can QI to a HTMLElement, which is + * not true for xul content. */ + + nsCOMPtr<nsIDOMDocument> domDoc; + rv = node->GetOwnerDocument(getter_AddRefs(domDoc)); + if (NS_FAILED(rv) || !domDoc) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMXULDocument> xul_document = do_QueryInterface(domDoc); + if (xul_document) + { + info->context = EPHY_EMBED_CONTEXT_NONE; + return NS_ERROR_FAILURE; + } + + mDOMDocument = domDoc; + + rv = mBrowser->GetEncoding (mCharset); + NS_ENSURE_SUCCESS (rv, rv); + + /* Get base URI and CSS view */ + nsCOMPtr<nsIDOMDocumentView> docView (do_QueryInterface (domDoc)); + NS_ENSURE_TRUE (docView, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDOMAbstractView> abstractView; + docView->GetDefaultView (getter_AddRefs (abstractView)); + NS_ENSURE_TRUE (abstractView, NS_ERROR_FAILURE); + /* the abstract view is really the DOM window */ + + mViewCSS = do_QueryInterface (abstractView); + NS_ENSURE_TRUE (mViewCSS, NS_ERROR_FAILURE); + + nsCOMPtr<nsIWebNavigation> webNav (do_GetInterface (abstractView, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + rv = webNav->GetCurrentURI (getter_AddRefs (mBaseURI)); + NS_ENSURE_SUCCESS (rv, rv); + + // Now we know that the page isn't a xul window, we can try and + // do something useful with it. + + PRUint16 type; + rv = node->GetNodeType(&type); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + PRBool has_image = PR_FALSE; + + nsCOMPtr<nsIDOMHTMLElement> element = do_QueryInterface(node); + if ((nsIDOMNode::ELEMENT_NODE == type) && element) + { + nsString uTag; + rv = element->GetLocalName(uTag); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCString tag; + NS_UTF16ToCString (uTag, NS_CSTRING_ENCODING_UTF8, tag); + + if (g_ascii_strcasecmp (tag.get(), "img") == 0) + { + nsString img; + nsCOMPtr <nsIDOMHTMLImageElement> image = + do_QueryInterface(node, &rv); + if (NS_FAILED(rv) || !image) return NS_ERROR_FAILURE; + + rv = image->GetSrc (img); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + SetStringProperty ("image", img); + info->context |= EPHY_EMBED_CONTEXT_IMAGE; + has_image = PR_TRUE; + } + else if (g_ascii_strcasecmp (tag.get(), "area") == 0) + { + nsCOMPtr <nsIDOMHTMLAreaElement> area = + do_QueryInterface(node, &rv); + if (NS_FAILED(rv) || !area) return NS_ERROR_FAILURE; + + // Parent node is the map itself + nsCOMPtr<nsIDOMNode> parentNode; + node->GetParentNode (getter_AddRefs(parentNode)); + + nsCOMPtr <nsIDOMHTMLMapElement> map = + do_QueryInterface(parentNode, &rv); + if (NS_FAILED(rv) || !area) return NS_ERROR_FAILURE; + + nsString mapName; + rv = map->GetName (mapName); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + // Now we are searching for all the images with a usemap attribute + nsCOMPtr<nsIDOMNodeList> imgs; + rv = mDOMDocument->GetElementsByTagName (nsString(imgLiteral), + getter_AddRefs (imgs)); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + PRUint32 imgs_count; + rv = imgs->GetLength (&imgs_count); + if (NS_FAILED (rv)) return NS_ERROR_FAILURE; + + for (PRUint32 i = 0; i < imgs_count; i++) + { + nsCOMPtr<nsIDOMNode> aNode; + rv = imgs->Item (i, getter_AddRefs (aNode)); + if (NS_FAILED (rv)) continue; + + nsCOMPtr<nsIDOMHTMLImageElement> img = + do_QueryInterface(aNode, &rv); + if (NS_FAILED(rv) || !img) continue; + + nsString imgMapName; + rv = img->GetUseMap (imgMapName); + if (NS_FAILED (rv)) continue; + + // usemap always starts with # + imgMapName.Cut (0,1); + + // Check if the current image is attached to the map we are looking for + if (imgMapName.Equals(mapName)) + { + nsString imgSrc; + rv = img->GetSrc (imgSrc); + if (NS_FAILED(rv)) continue; + + SetStringProperty ("image", imgSrc); + info->context |= EPHY_EMBED_CONTEXT_IMAGE; + has_image = PR_TRUE; + + break; + } + } + } + else if (g_ascii_strcasecmp (tag.get(), "input") == 0) + { + CheckInput (node); + } + else if (g_ascii_strcasecmp (tag.get(), "textarea") == 0) + { + info->context |= EPHY_EMBED_CONTEXT_INPUT; + } + else if (g_ascii_strcasecmp (tag.get(), "object") == 0) + { + nsCOMPtr<nsIDOMHTMLObjectElement> object; + object = do_QueryInterface (node); + if (!element) return NS_ERROR_FAILURE; + + nsString value; + object->GetType(value); + + nsCString cValue; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cValue); + + // MIME types are always lower case + if (g_str_has_prefix (cValue.get(), "image/")) + { + nsString img; + + rv = object->GetData (img); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCString cImg; + rv = ResolveBaseURL (img, cImg); + if (NS_FAILED (rv)) return NS_ERROR_FAILURE; + + SetStringProperty ("image", cImg.get()); + info->context |= EPHY_EMBED_CONTEXT_IMAGE; + has_image = PR_TRUE; + } + else + { + info->context = EPHY_EMBED_CONTEXT_NONE; + return NS_OK; + } + } + else if (g_ascii_strcasecmp (tag.get(), "html") == 0) + { + /* Clicked on part of the page without a <body>, so + * look for a background image in the body tag */ + nsCOMPtr<nsIDOMNodeList> nodeList; + + rv = mDOMDocument->GetElementsByTagName (nsString(bodyLiteral), + getter_AddRefs (nodeList)); + if (NS_SUCCEEDED (rv) && nodeList) + { + nsCOMPtr<nsIDOMNode> bodyNode; + nodeList->Item (0, getter_AddRefs (bodyNode)); + + nsString cssurl; + rv = GetCSSBackground (bodyNode, cssurl); + if (NS_SUCCEEDED (rv)) + { + nsCString bgimg; + rv = ResolveBaseURL (cssurl, bgimg); + if (NS_FAILED (rv)) + return NS_ERROR_FAILURE; + + SetStringProperty ("image", bgimg.get()); + info->context |= EPHY_EMBED_CONTEXT_IMAGE; + has_image = PR_TRUE; + } + } + } + } + + /* Is page framed ? */ + PRBool framed; + IsPageFramed (node, &framed); + SetIntProperty ("framed_page", framed); + + /* Bubble out, looking for items of interest */ + while (node) + { + nsCOMPtr <nsIDOMElement> dom_elem = do_QueryInterface(node); + if (dom_elem) + { + nsString value; + dom_elem->GetAttributeNS (nsString(xlinknsLiteral), + nsString(typeLiteral), value); + + nsCString cValue; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cValue); + + if (g_ascii_strcasecmp (cValue.get(), "simple") == 0) + { + info->context |= EPHY_EMBED_CONTEXT_LINK; + dom_elem->GetAttributeNS (nsString(xlinknsLiteral), + nsString(hrefLiteral), value); + + SetURIProperty (node, "link", value); + CheckLinkScheme (value); + } + } + + rv = node->GetNodeType(&type); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + element = do_QueryInterface(node); + if ((nsIDOMNode::ELEMENT_NODE == type) && element) + { + nsString uTag; + rv = element->GetLocalName(uTag); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCString tag; + NS_UTF16ToCString (uTag, NS_CSTRING_ENCODING_UTF8, tag); + + /* Link */ + if (g_ascii_strcasecmp (tag.get(), "a") == 0) + { + nsString tmp; + + rv = GatherTextUnder (node, tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("linktext", tmp); + + nsCOMPtr <nsIDOMHTMLAnchorElement> anchor = + do_QueryInterface(node); + + nsCString href; + anchor->GetHref (tmp); + NS_UTF16ToCString (tmp, NS_CSTRING_ENCODING_UTF8, href); + + if (g_str_has_prefix (href.get(), "mailto:")) + { + /* cut "mailto:" */ + href.Cut (0, 7); + + char *str = g_strdup (href.get()); + g_strdelimit (str, "?", '\0'); + + nsCString unescapedHref; + rv = Unescape (nsCString(str), unescapedHref); + if (NS_SUCCEEDED (rv) && unescapedHref.Length()) + { + SetStringProperty ("email", unescapedHref.get()); + info->context |= EPHY_EMBED_CONTEXT_EMAIL_LINK; + } + g_free (str); + } + + if (anchor && tmp.Length()) + { + info->context |= EPHY_EMBED_CONTEXT_LINK; + + SetURIProperty (node, "link", tmp); + CheckLinkScheme (tmp); + rv = anchor->GetHreflang (tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("link_lang", tmp); + rv = anchor->GetTarget (tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("link_target", tmp); + rv = anchor->GetRel (tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("link_rel", tmp); + rv = anchor->GetRev (tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("link_rev", tmp); + rv = element->GetTitle (tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("link_title", tmp); + rv = anchor->GetType (tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("link_type", tmp); + + nsCString linkType; + NS_UTF16ToCString (tmp, NS_CSTRING_ENCODING_UTF8, linkType); + + if (g_ascii_strcasecmp (linkType.get(), "text/smartbookmark") == 0) + { + SetIntProperty ("link_is_smart", TRUE); + + nsCOMPtr<nsIDOMNode> childNode; + node->GetFirstChild (getter_AddRefs(childNode)); + if (childNode) + { + nsCOMPtr <nsIDOMHTMLImageElement> image = + do_QueryInterface(childNode, &rv); + + if (image) + { + nsString img; + rv = image->GetSrc (img); + if (!NS_FAILED(rv)) + { + SetStringProperty ("image", img); + } + } + } + } + else + { + SetIntProperty ("link_is_smart", FALSE); + } + } + + } + else if (g_ascii_strcasecmp (tag.get(), "option") == 0) + { + info->context = EPHY_EMBED_CONTEXT_NONE; + return NS_OK; + } + else if (g_ascii_strcasecmp (tag.get(), "area") == 0) + { + info->context |= EPHY_EMBED_CONTEXT_LINK; + nsCOMPtr <nsIDOMHTMLAreaElement> area = + do_QueryInterface(node, &rv); + if (NS_SUCCEEDED(rv) && area) + { + nsString href; + rv = area->GetHref (href); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + SetURIProperty (node, "link", href); + CheckLinkScheme (href); + } + } + else if (g_ascii_strcasecmp (tag.get(), "input") == 0) + { + CheckInput (node); + } + else if (g_ascii_strcasecmp (tag.get(), "textarea") == 0) + { + info->context |= EPHY_EMBED_CONTEXT_INPUT; + } + + if (!has_image) + { + nsString cssurl; + rv = GetCSSBackground (node, cssurl); + if (NS_SUCCEEDED (rv)) + { + nsCString bgimg; + + rv = ResolveBaseURL (cssurl, bgimg); + if (NS_FAILED (rv)) + return NS_ERROR_FAILURE; + SetStringProperty ("image", bgimg.get()); + info->context |= EPHY_EMBED_CONTEXT_IMAGE; + has_image = PR_TRUE; + } + } + } + + nsCOMPtr<nsIDOMNode> parentNode; + node->GetParentNode (getter_AddRefs(parentNode)); + node = parentNode; + } + + return NS_OK; +} + +nsresult EventContext::GetCSSBackground (nsIDOMNode *node, nsAString& url) +{ + if (!mViewCSS) return NS_ERROR_NOT_INITIALIZED; + + nsresult rv; + + const PRUnichar bgimage[] = {'b', 'a', 'c', 'k', 'g', 'r', 'o', 'u', 'n', 'd', + '-', 'i', 'm', 'a', 'g', 'e', '\0'}; + + nsCOMPtr<nsIDOMElement> element = do_QueryInterface (node); + NS_ENSURE_TRUE (element, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDOMCSSStyleDeclaration> decl; + mViewCSS->GetComputedStyle (element, nsString(), + getter_AddRefs (decl)); + NS_ENSURE_TRUE (decl, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDOMCSSValue> CSSValue; + decl->GetPropertyCSSValue (nsString(bgimage), + getter_AddRefs (CSSValue)); + + nsCOMPtr<nsIDOMCSSPrimitiveValue> primitiveValue = + do_QueryInterface (CSSValue); + if (!primitiveValue) return NS_ERROR_FAILURE; + + PRUint16 type; + rv = primitiveValue->GetPrimitiveType (&type); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + if (type != nsIDOMCSSPrimitiveValue::CSS_URI) return NS_ERROR_FAILURE; + + rv = primitiveValue->GetStringValue (url); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + return NS_OK; +} + +nsresult EventContext::GetTargetCoords (nsIDOMEventTarget *aTarget, PRInt32 *aX, PRInt32 *aY) +{ + /* Calculate the node coordinates relative to the widget origin */ + nsCOMPtr<nsIDOMNSHTMLElement> elem (do_QueryInterface(aTarget)); + + PRInt32 x = 0, y = 0; + while (elem) + { + PRInt32 val; + elem->GetOffsetTop(&val); y += val; + elem->GetScrollTop(&val); y -= val; + elem->GetOffsetLeft(&val); x += val; + elem->GetScrollLeft(&val); x -= val; + + nsCOMPtr<nsIDOMElement> parent; + elem->GetOffsetParent (getter_AddRefs (parent)); + elem = do_QueryInterface(parent); + } + + *aX = x; + *aY = y; + + return NS_OK; +} + +nsresult EventContext::GetMouseEventInfo (nsIDOMMouseEvent *aMouseEvent, MozillaEmbedEvent *info) +{ + /* FIXME: casting 32-bit guint* to PRUint16* below will break on big-endian */ + PRUint16 btn = 1729; + aMouseEvent->GetButton (&btn); + + switch (btn) + { + /* mozilla's button counting is one-off from gtk+'s */ + case 0: + info->button = 1; + break; + case 1: + info->button = 2; + break; + case 2: + info->button = 3; + break; + + case (PRUint16) -1: + /* when the user submits a form with Return, mozilla synthesises + * a _mouse_ click event with btn=65535 (-1). + */ + default: + info->button = 0; + break; + } + + if (info->button != 0) + { + /* OTOH, casting only between (un)signedness is safe */ + aMouseEvent->GetScreenX ((PRInt32*)&info->x); + aMouseEvent->GetScreenY ((PRInt32*)&info->y); + } + else /* this is really a keyboard event */ + { + nsCOMPtr<nsIDOMEventTarget> eventTarget; + aMouseEvent->GetTarget (getter_AddRefs (eventTarget)); + + GetTargetCoords (eventTarget, (PRInt32*)&info->x, (PRInt32*)&info->y); + } + + /* be sure we are not clicking on the scroolbars */ + + nsCOMPtr<nsIDOMNSEvent> nsEvent = do_QueryInterface(aMouseEvent); + if (!nsEvent) return NS_ERROR_FAILURE; + +#ifdef MOZ_NSIDOMNSEVENT_GETISTRUSTED + /* make sure the event is trusted */ + PRBool isTrusted = PR_FALSE; + nsEvent->GetIsTrusted (&isTrusted); + if (!isTrusted) return NS_ERROR_UNEXPECTED; +#endif /* MOZ_NSIDOMNSEVENT_GETISTRUSTED */ + + nsresult rv; + nsCOMPtr<nsIDOMEventTarget> OriginalTarget; + rv = nsEvent->GetOriginalTarget(getter_AddRefs(OriginalTarget)); + if (NS_FAILED (rv) || !OriginalTarget) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMNode> OriginalNode = do_QueryInterface(OriginalTarget); + if (!OriginalNode) return NS_ERROR_FAILURE; + + nsString nodename; + OriginalNode->GetNodeName(nodename); + nsCString cNodeName; + NS_UTF16ToCString (nodename, NS_CSTRING_ENCODING_UTF8, cNodeName); + + if (g_ascii_strcasecmp (cNodeName.get(), "xul:scrollbarbutton") == 0 || + g_ascii_strcasecmp (cNodeName.get(), "xul:thumb") == 0 || + g_ascii_strcasecmp (cNodeName.get(), "xul:vbox") == 0 || + g_ascii_strcasecmp (cNodeName.get(), "xul:spacer") == 0 || + g_ascii_strcasecmp (cNodeName.get(), "xul:slider") == 0) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMEventTarget> EventTarget; + rv = aMouseEvent->GetTarget(getter_AddRefs(EventTarget)); + if (NS_FAILED (rv) || !EventTarget) return NS_ERROR_FAILURE; + + rv = GetEventContext (EventTarget, info); + if (NS_FAILED (rv)) return rv; + + /* Get the modifier */ + + PRBool mod_key; + + info->modifier = 0; + + aMouseEvent->GetAltKey(&mod_key); + if (mod_key) info->modifier |= GDK_MOD1_MASK; + + aMouseEvent->GetShiftKey(&mod_key); + if (mod_key) info->modifier |= GDK_SHIFT_MASK; + + /* no need to check GetMetaKey, it's always PR_FALSE, + * see widget/src/gtk2/nsWindow.cpp:InitMouseEvent + */ + + aMouseEvent->GetCtrlKey(&mod_key); + if (mod_key) info->modifier |= GDK_CONTROL_MASK; + + return NS_OK; +} + +nsresult EventContext::GetKeyEventInfo (nsIDOMKeyEvent *aKeyEvent, MozillaEmbedEvent *info) +{ +#ifdef MOZ_NSIDOMNSEVENT_GETISTRUSTED + /* make sure the event is trusted */ + nsCOMPtr<nsIDOMNSEvent> nsEvent (do_QueryInterface (aKeyEvent)); + NS_ENSURE_TRUE (nsEvent, NS_ERROR_FAILURE); + + PRBool isTrusted = PR_FALSE; + nsEvent->GetIsTrusted (&isTrusted); + if (!isTrusted) return NS_ERROR_UNEXPECTED; +#endif /* MOZ_NSIDOMNSEVENT_GETISTRUSTED */ + + + info->button = 0; + + nsresult rv; + PRUint32 keyCode; + rv = aKeyEvent->GetKeyCode(&keyCode); + if (NS_FAILED(rv)) return rv; + info->keycode = keyCode; + + nsCOMPtr<nsIDOMEventTarget> target; + rv = aKeyEvent->GetTarget(getter_AddRefs(target)); + if (NS_FAILED(rv) || !target) return NS_ERROR_FAILURE; + + GetTargetCoords (target, (PRInt32*)&info->x, (PRInt32*)&info->y); + + /* Context */ + rv = GetEventContext (target, info); + if (NS_FAILED(rv)) return rv; + + /* Get the modifier */ + + PRBool mod_key; + + info->modifier = 0; + + aKeyEvent->GetAltKey(&mod_key); + if (mod_key) info->modifier |= GDK_MOD1_MASK; + + aKeyEvent->GetShiftKey(&mod_key); + if (mod_key) info->modifier |= GDK_SHIFT_MASK; + + aKeyEvent->GetMetaKey(&mod_key); + if (mod_key) info->modifier |= GDK_MOD2_MASK; + + aKeyEvent->GetCtrlKey(&mod_key); + if (mod_key) info->modifier |= GDK_CONTROL_MASK; + + return NS_OK; +} + +nsresult EventContext::IsPageFramed (nsIDOMNode *node, PRBool *Framed) +{ + nsresult rv; + + nsCOMPtr<nsIDOMDocument> mainDocument; + rv = mBrowser->GetDocument (getter_AddRefs(mainDocument)); + if (NS_FAILED (rv) || !mainDocument) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMDocument> nodeDocument; + rv = node->GetOwnerDocument (getter_AddRefs(nodeDocument)); + if (NS_FAILED (rv) || !nodeDocument) return NS_ERROR_FAILURE; + + *Framed = (mainDocument != nodeDocument); + + return NS_OK; +} + +nsresult EventContext::GetTargetDocument (nsIDOMDocument **domDoc) +{ + if (!mDOMDocument) return NS_ERROR_FAILURE; + + *domDoc = mDOMDocument.get(); + + NS_IF_ADDREF(*domDoc); + + return NS_OK; +} + +nsresult EventContext::CheckInput (nsIDOMNode *aNode) +{ + const PRUnichar typeLiteral[] = { 't', 'y', 'p', 'e', '\0' }; + + nsCOMPtr<nsIDOMElement> element; + element = do_QueryInterface (aNode); + if (!element) return NS_ERROR_FAILURE; + + nsString uValue; + element->GetAttribute (nsString(typeLiteral), uValue); + + nsCString value; + NS_UTF16ToCString (uValue, NS_CSTRING_ENCODING_UTF8, value); + + if (g_ascii_strcasecmp (value.get(), "image") == 0) + { + mEmbedEvent->context |= EPHY_EMBED_CONTEXT_IMAGE; + nsCOMPtr<nsIDOMHTMLInputElement> input; + input = do_QueryInterface (aNode); + if (!input) return NS_ERROR_FAILURE; + + nsresult rv; + nsString img; + rv = input->GetSrc (img); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCString cImg; + rv = ResolveBaseURL (img, cImg); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + SetStringProperty ("image", cImg.get()); + } + else if (g_ascii_strcasecmp (value.get(), "radio") != 0 && + g_ascii_strcasecmp (value.get(), "submit") != 0 && + g_ascii_strcasecmp (value.get(), "reset") != 0 && + g_ascii_strcasecmp (value.get(), "hidden") != 0 && + g_ascii_strcasecmp (value.get(), "button") != 0 && + g_ascii_strcasecmp (value.get(), "checkbox") != 0) + { + mEmbedEvent->context |= EPHY_EMBED_CONTEXT_INPUT; + + if (g_ascii_strcasecmp (value.get(), "password") == 0) + { + mEmbedEvent->context |= EPHY_EMBED_CONTEXT_INPUT_PASSWORD; + } + } + + return NS_OK; +} + +nsresult EventContext::CheckLinkScheme (const nsAString &link) +{ + nsCOMPtr<nsIURI> uri; + EphyUtils::NewURI (getter_AddRefs (uri), link); + if (!uri) return NS_ERROR_FAILURE; + + nsresult rv; + nsCString scheme; + rv = uri->GetScheme (scheme); + if (NS_FAILED (rv)) return NS_ERROR_FAILURE; + + if (g_ascii_strcasecmp (scheme.get(), "http") == 0 || + g_ascii_strcasecmp (scheme.get(), "https") == 0 || + g_ascii_strcasecmp (scheme.get(), "ftp") == 0 || + g_ascii_strcasecmp (scheme.get(), "file") == 0 || + g_ascii_strcasecmp (scheme.get(), "smb") == 0 || + g_ascii_strcasecmp (scheme.get(), "sftp") == 0 || + g_ascii_strcasecmp (scheme.get(), "ssh") == 0 || + g_ascii_strcasecmp (scheme.get(), "data") == 0 || + g_ascii_strcasecmp (scheme.get(), "resource") == 0 || + g_ascii_strcasecmp (scheme.get(), "about") == 0 || + g_ascii_strcasecmp (scheme.get(), "gopher") == 0) + { + SetIntProperty ("link-has-web-scheme", TRUE); + } + + return NS_OK; +} + +nsresult EventContext::SetIntProperty (const char *name, int value) +{ + + GValue *val = g_new0 (GValue, 1); + + g_value_init (val, G_TYPE_INT); + + g_value_set_int (val, value); + + mozilla_embed_event_set_property (mEmbedEvent, name, val); + + return NS_OK; +} + +nsresult EventContext::SetStringProperty (const char *name, const char *value) +{ + GValue *val = g_new0 (GValue, 1); + + g_value_init (val, G_TYPE_STRING); + + g_value_set_string (val, value); + + mozilla_embed_event_set_property (mEmbedEvent, name, val); + + return NS_OK; +} + +nsresult EventContext::SetStringProperty (const char *name, const nsAString &value) +{ + nsCString cValue; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cValue); + return SetStringProperty (name, cValue.get()); +} + +nsresult EventContext::SetURIProperty (nsIDOMNode *node, const char *name, const nsACString &value) +{ + nsresult rv; + nsCOMPtr<nsIURI> uri; + rv = EphyUtils::NewURI (getter_AddRefs (uri), value, mCharset.Length () ? mCharset.get() : nsnull, mBaseURI); + if (NS_SUCCEEDED (rv) && uri) + { + /* Hide password part */ + nsCString user; + uri->GetUsername (user); + uri->SetUserPass (user); + + nsCString spec; + uri->GetSpec (spec); + rv = SetStringProperty (name, spec.get()); + } + else + { + rv = SetStringProperty (name, nsCString(value).get()); + } + + return rv; +} + +nsresult EventContext::SetURIProperty (nsIDOMNode *node, const char *name, const nsAString &value) +{ + nsCString cValue; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cValue); + return SetURIProperty (node, name, cValue); +} + +/* static */ +PRBool +EventContext::CheckKeyPress (nsIDOMKeyEvent *aEvent) +{ + PRBool retval = PR_FALSE; + + /* make sure the event is trusted */ + nsCOMPtr<nsIDOMNSEvent> nsEvent (do_QueryInterface (aEvent)); + NS_ENSURE_TRUE (nsEvent, retval); + PRBool isTrusted = PR_FALSE; + nsEvent->GetIsTrusted (&isTrusted); + if (!isTrusted) return retval; + + /* check for alt/ctrl */ + PRBool isCtrl = PR_FALSE, isAlt = PR_FALSE; + aEvent->GetCtrlKey (&isCtrl); + aEvent->GetAltKey (&isAlt); + if (isCtrl || isAlt) return retval; + + nsCOMPtr<nsIDOMNSUIEvent> uiEvent (do_QueryInterface (aEvent)); + NS_ENSURE_TRUE (uiEvent, retval); + + /* check for already handled event */ + PRBool isPrevented = PR_FALSE; + uiEvent->GetPreventDefault (&isPrevented); + if (isPrevented) return retval; + + /* check for form controls */ + nsresult rv; + nsCOMPtr<nsIDOMEventTarget> target; + rv = aEvent->GetTarget (getter_AddRefs (target)); + NS_ENSURE_SUCCESS (rv, retval); + + nsCOMPtr<nsIDOMHTMLInputElement> inputElement (do_QueryInterface (target)); + if (inputElement) + { + nsString type; + inputElement->GetType (type); + + nsCString (cType); + NS_UTF16ToCString (type, NS_CSTRING_ENCODING_UTF8, cType); + + if (g_ascii_strcasecmp (cType.get(), "text") == 0 || + g_ascii_strcasecmp (cType.get(), "password") == 0 || + g_ascii_strcasecmp (cType.get(), "file") == 0) return retval; + } + + nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea; + nsCOMPtr<nsIDOMHTMLSelectElement> selectElement; + nsCOMPtr<nsIDOMHTMLIsIndexElement> indexElement; + nsCOMPtr<nsIDOMHTMLObjectElement> objectElement; + nsCOMPtr<nsIDOMHTMLEmbedElement> embedElement; + + if ((textArea = do_QueryInterface (target)) || + (selectElement = do_QueryInterface (target)) || + (indexElement = do_QueryInterface (target)) || + (objectElement = do_QueryInterface (target)) || + (embedElement = do_QueryInterface (target))) return retval; + + /* check for design mode */ + nsCOMPtr<nsIDOMNode> node (do_QueryInterface (target, &rv)); + NS_ENSURE_SUCCESS (rv, PR_FALSE); + + nsCOMPtr<nsIDOMDocument> doc; + rv = node->GetOwnerDocument (getter_AddRefs (doc)); + NS_ENSURE_SUCCESS (rv, retval); + + nsCOMPtr<nsIDOMXULDocument> xul_document (do_QueryInterface(doc, &rv)); + if (xul_document) return retval; + + nsCOMPtr<nsIDOMNSHTMLDocument> htmlDoc (do_QueryInterface (doc)); + if (htmlDoc) + { + nsString uDesign; + rv = htmlDoc->GetDesignMode (uDesign); + NS_ENSURE_SUCCESS (rv, retval); + + nsCString design; + NS_UTF16ToCString (uDesign, NS_CSTRING_ENCODING_UTF8, design); + + retval = g_ascii_strcasecmp (design.get(), "on") != 0; + } + else + { + retval = PR_TRUE; + } + + return retval; +} |