[epiphany] Allow per-site autoplay policies.



commit d048aafb8be90b5e8a9622aa5c2c42bd8a76d7b2
Author: Charlie Turner <cturner igalia com>
Date:   Mon Jun 29 15:33:39 2020 +0100

    Allow per-site autoplay policies.
    
    Denying autoplay can break websites that use it for stylistic
    effects. On the other hand, it can be increadibly annoying to be
    spammed with videos autoplaying.
    
    By default, videos can autoplay so long as they have no audio (or the
    audio is muted). Alternatively, users can allow all videos to autoplay
    even with audio, or to deny all attempts to autoplay video. Users can
    make these decisions using the security pop-over on a
    per security-origin basis.

 data/org.gnome.epiphany.gschema.xml |  5 +++
 embed/ephy-web-view.c               | 66 +++++++++++++++++++++++++++++++++----
 lib/ephy-permissions-manager.c      |  2 ++
 lib/ephy-permissions-manager.h      |  1 +
 lib/widgets/ephy-security-popover.c | 36 +++++++++++++++-----
 5 files changed, 94 insertions(+), 16 deletions(-)
---
diff --git a/data/org.gnome.epiphany.gschema.xml b/data/org.gnome.epiphany.gschema.xml
index aff5400ca..f5e0c256f 100644
--- a/data/org.gnome.epiphany.gschema.xml
+++ b/data/org.gnome.epiphany.gschema.xml
@@ -429,5 +429,10 @@
                        <summary>Decision to apply when advertisement permission is requested for this 
host</summary>
                        <description>This option is used to save whether a given host has been given 
permission to allow advertisements. The “undecided” default means the browser global setting is used, while 
“allow” and “deny” tell it to automatically make the decision upon request.</description>
                </key>
+               <key name="autoplay-permission" enum="org.gnome.Epiphany.Permission">
+                       <default>'undecided'</default>
+                       <summary>Decision to apply when an autoplay policy is requested for this 
host</summary>
+                       <description>This option is used to save whether a given host has been given 
permission to autoplay. The “undecided” default means to allow autoplay of muted media, while “allow” and 
“deny” tell it to allow / deny all requests to autoplay media respectively.</description>
+               </key>
        </schema>
 </schemalist>
diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c
index e0b4eebe7..a0bf84d7d 100644
--- a/embed/ephy-web-view.c
+++ b/embed/ephy-web-view.c
@@ -812,10 +812,46 @@ process_terminated_cb (EphyWebView                       *web_view,
 }
 
 static gboolean
-decide_policy_cb (WebKitWebView            *web_view,
-                  WebKitPolicyDecision     *decision,
-                  WebKitPolicyDecisionType  decision_type,
-                  gpointer                  user_data)
+decide_navigation (WebKitWebView        *web_view,
+                   WebKitPolicyDecision *decision,
+                   gpointer              user_data)
+{
+  EphyEmbedShell *shell = ephy_embed_shell_get_default ();
+  WebKitWebsitePolicies *website_policies = NULL;
+  g_autofree gchar *origin = NULL;
+  WebKitNavigationPolicyDecision *navigation_policy_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
+  WebKitNavigationAction *navigation_action = webkit_navigation_policy_decision_get_navigation_action 
(navigation_policy_decision);
+  WebKitURIRequest *request = webkit_navigation_action_get_request (navigation_action);
+  const gchar *navigation_uri = webkit_uri_request_get_uri (request);
+  EphyPermission permission = EPHY_PERMISSION_UNDECIDED;
+
+  origin = ephy_uri_to_security_origin (navigation_uri);
+  if (origin)
+    permission = ephy_permissions_manager_get_permission (ephy_embed_shell_get_permissions_manager (shell),
+                                                          EPHY_PERMISSION_TYPE_AUTOPLAY_POLICY,
+                                                          origin);
+
+  switch (permission) {
+    case EPHY_PERMISSION_UNDECIDED:
+      website_policies = webkit_website_policies_new_with_policies ("autoplay", 
WEBKIT_AUTOPLAY_ALLOW_WITHOUT_SOUND, NULL);
+      break;
+    case EPHY_PERMISSION_PERMIT:
+      website_policies = webkit_website_policies_new_with_policies ("autoplay", WEBKIT_AUTOPLAY_ALLOW, NULL);
+      break;
+    case EPHY_PERMISSION_DENY:
+      website_policies = webkit_website_policies_new_with_policies ("autoplay", WEBKIT_AUTOPLAY_DENY, NULL);
+      break;
+  }
+
+  webkit_policy_decision_use_with_policies (decision, website_policies);
+  g_object_unref (website_policies);
+  return TRUE;
+}
+
+static gboolean
+decide_resource (WebKitWebView        *web_view,
+                 WebKitPolicyDecision *decision,
+                 gpointer              user_data)
 {
   WebKitResponsePolicyDecision *response_decision;
   WebKitURIResponse *response;
@@ -826,9 +862,6 @@ decide_policy_cb (WebKitWebView            *web_view,
   const char *request_uri;
   gboolean is_main_resource;
 
-  if (decision_type != WEBKIT_POLICY_DECISION_TYPE_RESPONSE)
-    return FALSE;
-
   /* If WebKit can handle the MIME type, let it.
    * Otherwise, we'll start a download.
    */
@@ -881,6 +914,25 @@ decide_policy_cb (WebKitWebView            *web_view,
   return TRUE;
 }
 
+static gboolean
+decide_policy_cb (WebKitWebView            *web_view,
+                  WebKitPolicyDecision     *decision,
+                  WebKitPolicyDecisionType  decision_type,
+                  gpointer                  user_data)
+{
+  switch (decision_type) {
+    case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
+      return decide_navigation (web_view, decision, user_data);
+    case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
+      return decide_resource (web_view, decision, user_data);
+    case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
+      /* not handled */
+      break;
+  }
+
+  return TRUE;
+}
+
 typedef struct {
   EphyWebView *web_view;
   WebKitPermissionRequest *request;
diff --git a/lib/ephy-permissions-manager.c b/lib/ephy-permissions-manager.c
index 45395c5ff..4079c759e 100644
--- a/lib/ephy-permissions-manager.c
+++ b/lib/ephy-permissions-manager.c
@@ -167,6 +167,8 @@ permission_type_to_string (EphyPermissionType type)
       return "video-device-permission";
     case EPHY_PERMISSION_TYPE_SHOW_ADS:
       return "advertisement-permission";
+    case EPHY_PERMISSION_TYPE_AUTOPLAY_POLICY:
+      return "autoplay-permission";
     default:
       g_assert_not_reached ();
   }
diff --git a/lib/ephy-permissions-manager.h b/lib/ephy-permissions-manager.h
index caba693cc..aab47c17c 100644
--- a/lib/ephy-permissions-manager.h
+++ b/lib/ephy-permissions-manager.h
@@ -43,6 +43,7 @@ typedef enum {
   EPHY_PERMISSION_TYPE_ACCESS_MICROPHONE,
   EPHY_PERMISSION_TYPE_ACCESS_WEBCAM,
   EPHY_PERMISSION_TYPE_SHOW_ADS,
+  EPHY_PERMISSION_TYPE_AUTOPLAY_POLICY,
 } EphyPermissionType;
 
 EphyPermissionsManager *ephy_permissions_manager_new            (void);
diff --git a/lib/widgets/ephy-security-popover.c b/lib/widgets/ephy-security-popover.c
index 7f32102ff..68a8be9c5 100644
--- a/lib/widgets/ephy-security-popover.c
+++ b/lib/widgets/ephy-security-popover.c
@@ -65,6 +65,7 @@ struct _EphySecurityPopover {
   GtkWidget *access_location_combobox;
   GtkWidget *access_microphone_combobox;
   GtkWidget *access_webcam_combobox;
+  GtkWidget *autoplay_combobox;
   GtkWidget *grid;
   GTlsCertificate *certificate;
   GTlsCertificateFlags tls_errors;
@@ -155,6 +156,7 @@ ephy_security_popover_set_address (EphySecurityPopover *popover,
   set_permission_combobox_state (permissions_manager, EPHY_PERMISSION_TYPE_ACCESS_LOCATION, origin, 
popover->access_location_combobox);
   set_permission_combobox_state (permissions_manager, EPHY_PERMISSION_TYPE_ACCESS_MICROPHONE, origin, 
popover->access_microphone_combobox);
   set_permission_combobox_state (permissions_manager, EPHY_PERMISSION_TYPE_ACCESS_WEBCAM, origin, 
popover->access_webcam_combobox);
+  set_permission_combobox_state (permissions_manager, EPHY_PERMISSION_TYPE_AUTOPLAY_POLICY, origin, 
popover->autoplay_combobox);
 }
 
 static void
@@ -482,11 +484,20 @@ on_access_webcam_combobox_changed (GtkComboBox         *box,
   handle_permission_combobox_changed (popover, gtk_combo_box_get_active (box), 
EPHY_PERMISSION_TYPE_ACCESS_WEBCAM);
 }
 
+static void
+on_autoplay_policy_combobox_changed (GtkComboBox         *box,
+                                     EphySecurityPopover *popover)
+{
+  handle_permission_combobox_changed (popover, gtk_combo_box_get_active (box), 
EPHY_PERMISSION_TYPE_AUTOPLAY_POLICY);
+}
+
 static GtkWidget *
 add_permission_combobox (EphySecurityPopover *popover,
                          const gchar         *name,
                          gpointer             callback,
-                         gboolean             no_ask)
+                         GtkSizeGroup        *size_group,
+                         gboolean             no_ask,
+                         const gchar         *third_option_name)
 {
   GtkWidget *widget;
   GtkWidget *hbox;
@@ -503,11 +514,14 @@ add_permission_combobox (EphySecurityPopover *popover,
   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), _("Allow"));
   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), _("Deny"));
 
-  if (!no_ask)
-    gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), _("Ask"));
+  if (!no_ask) {
+    const gchar *name = third_option_name == NULL ? _("Ask") : third_option_name;
+    gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), _(name));
+  }
 
   gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 6);
   g_signal_connect (widget, "changed", G_CALLBACK (callback), popover);
+  gtk_size_group_add_widget (size_group, widget);
 
   return widget;
 }
@@ -517,6 +531,7 @@ ephy_security_popover_init (EphySecurityPopover *popover)
 {
   GtkWidget *permissions;
   GtkWidget *box;
+  g_autoptr (GtkSizeGroup) combo_box_size_group = NULL;
   g_autofree char *label = g_strdup_printf ("<b>%s</b>", _("Permissions"));
 
   popover->grid = gtk_grid_new ();
@@ -553,12 +568,15 @@ ephy_security_popover_init (EphySecurityPopover *popover)
   gtk_grid_attach (GTK_GRID (popover->grid), permissions, 0, 4, 2, 1);
 
   popover->permission_pos = 5;
-  popover->ad_combobox = add_permission_combobox (popover, _("Advertisements"), on_ad_combobox_changed, 
TRUE);
-  popover->notification_combobox = add_permission_combobox (popover, _("Notifications"), 
on_notification_combobox_changed, FALSE);
-  popover->save_password_combobox = add_permission_combobox (popover, _("Password saving"), 
on_save_password_combobox_changed, FALSE);
-  popover->access_location_combobox = add_permission_combobox (popover, _("Location access"), 
on_access_location_combobox_changed, FALSE);
-  popover->access_microphone_combobox = add_permission_combobox (popover, _("Microphone access"), 
on_access_microphone_combobox_changed, FALSE);
-  popover->access_webcam_combobox = add_permission_combobox (popover, _("Webcam access"), 
on_access_webcam_combobox_changed, FALSE);
+  combo_box_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+  popover->ad_combobox = add_permission_combobox (popover, _("Advertisements"), on_ad_combobox_changed, 
combo_box_size_group, TRUE, NULL);
+  popover->notification_combobox = add_permission_combobox (popover, _("Notifications"), 
on_notification_combobox_changed, combo_box_size_group, FALSE, NULL);
+  popover->save_password_combobox = add_permission_combobox (popover, _("Password saving"), 
on_save_password_combobox_changed, combo_box_size_group, FALSE, NULL);
+  popover->access_location_combobox = add_permission_combobox (popover, _("Location access"), 
on_access_location_combobox_changed, combo_box_size_group, FALSE, NULL);
+  popover->access_microphone_combobox = add_permission_combobox (popover, _("Microphone access"), 
on_access_microphone_combobox_changed, combo_box_size_group, FALSE, NULL);
+  popover->access_webcam_combobox = add_permission_combobox (popover, _("Webcam access"), 
on_access_webcam_combobox_changed, combo_box_size_group, FALSE, NULL);
+  popover->autoplay_combobox = add_permission_combobox (popover, _("Media autoplay"), 
on_autoplay_policy_combobox_changed, combo_box_size_group, FALSE, "Without Sound");
 
   gtk_container_add (GTK_CONTAINER (popover), popover->grid);
   gtk_widget_show_all (popover->grid);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]