Bug 1509266 - [1.3] Extend element information passed to ContentDelegate.onContextMenu. r=snorp,agi

Differential Revision: https://phabricator.services.mozilla.com/D12967

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Eugen Sawin 2018-11-27 20:29:04 +00:00
Родитель 1f285bb075
Коммит 29411ef725
4 изменённых файлов: 106 добавлений и 52 удалений

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

@ -257,31 +257,37 @@ class GeckoViewContentChild extends GeckoViewChildModule {
switch (aEvent.type) { switch (aEvent.type) {
case "contextmenu": case "contextmenu":
function nearestParentHref(node) { function nearestParentAttribute(aNode, aAttribute) {
while (node && !node.href) { while (aNode && aNode.hasAttribute &&
node = node.parentNode; !aNode.hasAttribute(aAttribute)) {
aNode = aNode.parentNode;
} }
return node && node.href; return aNode && aNode.getAttribute && aNode.getAttribute(aAttribute);
} }
const node = aEvent.composedTarget; const node = aEvent.composedTarget;
const hrefNode = nearestParentHref(node); const uri = nearestParentAttribute(node, "href");
const title = nearestParentAttribute(node, "title");
const alt = nearestParentAttribute(node, "alt");
const elementType = ChromeUtils.getClassName(node); const elementType = ChromeUtils.getClassName(node);
const isImage = elementType === "HTMLImageElement"; const isImage = elementType === "HTMLImageElement";
const isMedia = elementType === "HTMLVideoElement" || const isMedia = elementType === "HTMLVideoElement" ||
elementType === "HTMLAudioElement"; elementType === "HTMLAudioElement";
const elementSrc = (isImage || isMedia) && (node.currentSrc || node.src);
if (hrefNode || isImage || isMedia) { if (uri || isImage || isMedia) {
this.eventDispatcher.sendRequest({ const msg = {
type: "GeckoView:ContextMenu", type: "GeckoView:ContextMenu",
screenX: aEvent.screenX, screenX: aEvent.screenX,
screenY: aEvent.screenY, screenY: aEvent.screenY,
uri: hrefNode, uri,
title,
alt,
elementType, elementType,
elementSrc: (isImage || isMedia) elementSrc: elementSrc || null,
? node.currentSrc || node.src };
: null,
}); this.eventDispatcher.sendRequest(msg);
aEvent.preventDefault(); aEvent.preventDefault();
} }
break; break;

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

@ -21,5 +21,8 @@
classifier. classifier.
- Added a `protected` empty constructor to all field-only classes so that apps - Added a `protected` empty constructor to all field-only classes so that apps
can mock these classes in tests. can mock these classes in tests.
- Added `ContentDelegate.ContextElement` to extend the information passed to
`ContentDelegate#onContextMenu`. Extended information includes the element's
title and alt attributes.
[api-version]: 723adca536354bfa81afb83da5045ea6de8aa602 [api-version]: 8cfd04a09e7a242b3da22ccdd55c88a2aca2ba6d

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

@ -322,20 +322,22 @@ package org.mozilla.geckoview {
public static interface GeckoSession.ContentDelegate { public static interface GeckoSession.ContentDelegate {
method public void onCloseRequest(org.mozilla.geckoview.GeckoSession); method public void onCloseRequest(org.mozilla.geckoview.GeckoSession);
method public void onContextMenu(org.mozilla.geckoview.GeckoSession, int, int, java.lang.String, int, java.lang.String); method public void onContextMenu(org.mozilla.geckoview.GeckoSession, int, int, org.mozilla.geckoview.GeckoSession.ContentDelegate.ContextElement);
method public void onCrash(org.mozilla.geckoview.GeckoSession); method public void onCrash(org.mozilla.geckoview.GeckoSession);
method public void onExternalResponse(org.mozilla.geckoview.GeckoSession, org.mozilla.geckoview.GeckoSession.WebResponseInfo); method public void onExternalResponse(org.mozilla.geckoview.GeckoSession, org.mozilla.geckoview.GeckoSession.WebResponseInfo);
method public void onFirstComposite(org.mozilla.geckoview.GeckoSession); method public void onFirstComposite(org.mozilla.geckoview.GeckoSession);
method public void onFocusRequest(org.mozilla.geckoview.GeckoSession); method public void onFocusRequest(org.mozilla.geckoview.GeckoSession);
method public void onFullScreen(org.mozilla.geckoview.GeckoSession, boolean); method public void onFullScreen(org.mozilla.geckoview.GeckoSession, boolean);
method public void onTitleChange(org.mozilla.geckoview.GeckoSession, java.lang.String); method public void onTitleChange(org.mozilla.geckoview.GeckoSession, java.lang.String);
field public static final int ELEMENT_TYPE_AUDIO = 3;
field public static final int ELEMENT_TYPE_IMAGE = 1;
field public static final int ELEMENT_TYPE_NONE = 0;
field public static final int ELEMENT_TYPE_VIDEO = 2;
} }
public static interface GeckoSession.ContentDelegate.ElementType implements java.lang.annotation.Annotation { public static final class GeckoSession.ContentDelegate.ContextElement {
ctor protected ContextElement(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
field public final java.lang.String altText;
field public final java.lang.String linkUri;
field public final java.lang.String srcUri;
field public final java.lang.String title;
field public final int type;
} }
public static final class GeckoSession.FinderResult { public static final class GeckoSession.FinderResult {

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

@ -364,15 +364,19 @@ public class GeckoSession implements Parcelable {
close(); close();
delegate.onCrash(GeckoSession.this); delegate.onCrash(GeckoSession.this);
} else if ("GeckoView:ContextMenu".equals(event)) { } else if ("GeckoView:ContextMenu".equals(event)) {
final int type = getContentElementType( final ContentDelegate.ContextElement elem =
message.getString("elementType")); new ContentDelegate.ContextElement(
message.getString("uri"),
message.getString("title"),
message.getString("alt"),
message.getString("elementType"),
message.getString("elementSrc"));
delegate.onContextMenu(GeckoSession.this, delegate.onContextMenu(GeckoSession.this,
message.getInt("screenX"), message.getInt("screenX"),
message.getInt("screenY"), message.getInt("screenY"),
message.getString("uri"), elem);
type,
message.getString("elementSrc"));
} else if ("GeckoView:DOMTitleChanged".equals(event)) { } else if ("GeckoView:DOMTitleChanged".equals(event)) {
delegate.onTitleChange(GeckoSession.this, delegate.onTitleChange(GeckoSession.this,
message.getString("title")); message.getString("title"));
@ -2498,17 +2502,6 @@ public class GeckoSession implements Parcelable {
void onSecurityChange(GeckoSession session, SecurityInformation securityInfo); void onSecurityChange(GeckoSession session, SecurityInformation securityInfo);
} }
private static int getContentElementType(final String name) {
if ("HTMLImageElement".equals(name)) {
return ContentDelegate.ELEMENT_TYPE_IMAGE;
} else if ("HTMLVideoElement".equals(name)) {
return ContentDelegate.ELEMENT_TYPE_VIDEO;
} else if ("HTMLAudioElement".equals(name)) {
return ContentDelegate.ELEMENT_TYPE_AUDIO;
}
return ContentDelegate.ELEMENT_TYPE_NONE;
}
/** /**
* WebResponseInfo contains information about a single web response. * WebResponseInfo contains information about a single web response.
*/ */
@ -2557,14 +2550,6 @@ public class GeckoSession implements Parcelable {
} }
public interface ContentDelegate { public interface ContentDelegate {
@IntDef({ELEMENT_TYPE_NONE, ELEMENT_TYPE_IMAGE, ELEMENT_TYPE_VIDEO,
ELEMENT_TYPE_AUDIO})
/* package */ @interface ElementType {}
static final int ELEMENT_TYPE_NONE = 0;
static final int ELEMENT_TYPE_IMAGE = 1;
static final int ELEMENT_TYPE_VIDEO = 2;
static final int ELEMENT_TYPE_AUDIO = 3;
/** /**
* A page title was discovered in the content or updated after the content * A page title was discovered in the content or updated after the content
* loaded. * loaded.
@ -2596,6 +2581,69 @@ public class GeckoSession implements Parcelable {
*/ */
void onFullScreen(GeckoSession session, boolean fullScreen); void onFullScreen(GeckoSession session, boolean fullScreen);
/**
* Element details for onContextMenu callbacks.
*/
public static final class ContextElement {
@IntDef({TYPE_NONE, TYPE_IMAGE, TYPE_VIDEO, TYPE_AUDIO})
/* package */ @interface Type {}
static final int TYPE_NONE = 0;
static final int TYPE_IMAGE = 1;
static final int TYPE_VIDEO = 2;
static final int TYPE_AUDIO = 3;
/**
* The link URI (href) of the element.
*/
public final @Nullable String linkUri;
/**
* The title text of the element.
*/
public final @Nullable String title;
/**
* The alternative text (alt) for the element.
*/
public final @Nullable String altText;
/**
* The type of the element.
* One of the {@link ContextElement#TYPE_NONE} flags.
*/
public final @Type int type;
/**
* The source URI (src) of the element.
* Set for (nested) media elements.
*/
public final @Nullable String srcUri;
protected ContextElement(
final @Nullable String linkUri,
final @Nullable String title,
final @Nullable String altText,
final @NonNull String typeStr,
final @Nullable String srcUri) {
this.linkUri = linkUri;
this.title = title;
this.altText = altText;
this.type = getType(typeStr);
this.srcUri = srcUri;
}
private static int getType(final String name) {
if ("HTMLImageElement".equals(name)) {
return TYPE_IMAGE;
} else if ("HTMLVideoElement".equals(name)) {
return TYPE_VIDEO;
} else if ("HTMLAudioElement".equals(name)) {
return TYPE_AUDIO;
}
return TYPE_NONE;
}
}
/** /**
* A user has initiated the context menu via long-press. * A user has initiated the context menu via long-press.
@ -2605,16 +2653,11 @@ public class GeckoSession implements Parcelable {
* @param session The GeckoSession that initiated the callback. * @param session The GeckoSession that initiated the callback.
* @param screenX The screen coordinates of the press. * @param screenX The screen coordinates of the press.
* @param screenY The screen coordinates of the press. * @param screenY The screen coordinates of the press.
* @param uri The URI of the pressed link, set for links and * @param element The details for the pressed element.
* image-links.
* @param elementType The type of the pressed element.
* One of the {@link ContentDelegate#ELEMENT_TYPE_NONE} flags.
* @param elementSrc The source URI of the pressed element, set for
* (nested) images and media elements.
*/ */
void onContextMenu(GeckoSession session, int screenX, int screenY, void onContextMenu(@NonNull GeckoSession session,
String uri, @ElementType int elementType, int screenX, int screenY,
String elementSrc); @NonNull ContextElement element);
/** /**
* This is fired when there is a response that cannot be handled * This is fired when there is a response that cannot be handled