Commit cc557e4bb961b40ffbc0c19d2727bad493bc87ff

Authored by samuel thibault
0 parents
Exists in master

import current version of my script

build 0 → 100755
  1 +++ a/build
... ... @@ -0,0 +1,93 @@
  1 +#!/bin/sh
  2 +# Usage:
  3 +# - define exp_srcpkg to the expected source package name
  4 +# - define srcdir to $(dirname $0)
  5 +# - source this
  6 +
  7 +current_testing=buster
  8 +
  9 +srcpkg=$(dpkg-parsechangelog -S Source)
  10 +
  11 +# Check that package matches called script
  12 +if [ "$srcpkg" != $exp_srcpkg ]
  13 +then
  14 + echo This script is only meant to be run from a $exp_srcpkg Debian source directory
  15 + exit 1
  16 +fi
  17 +
  18 +# Get package version
  19 +version=$(dpkg-parsechangelog -S Version)
  20 +mainversion=${version%%.*}
  21 +
  22 +# drop any previous hypra patch list
  23 +sed -i -e '/^# hypra/,$d' debian/patches/series
  24 +
  25 +# drop any previous hypra changelog
  26 +case $version in
  27 + *+hypra*)
  28 + version=${version%+hypra*}
  29 + sed -i -e "1,/^$/d" -e "1,/^$/d" -e "1,/^$/d" debian/changelog
  30 + ;;
  31 + *) ;;
  32 +esac
  33 +
  34 +# check for patch series file
  35 +if [ ! -f "$srcdir/series-$mainversion" ]
  36 +then
  37 + echo We need to update the patch series to version $mainversion
  38 + exit 2
  39 +fi
  40 +
  41 +dist=$(dpkg-parsechangelog -S Distribution)
  42 +
  43 +# start new changelog entry
  44 +dch --newversion $version+hypra$(cat "$srcdir/version") "Hypra-patched upload"
  45 +
  46 +# start patch series
  47 +echo "# hypra" >> debian/patches/series
  48 +
  49 +# feed patches
  50 +for i in $(cat "$srcdir/series-$mainversion")
  51 +do
  52 + # Avoid commented patches
  53 + case $i in
  54 + \#*) continue ;;
  55 + *) ;;
  56 + esac
  57 +
  58 + cp -f "$srcdir/patches-$mainversion/$i" debian/patches/
  59 + echo "$i" >> debian/patches/series
  60 + dch "$(head -n 1 "debian/patches/$i")"
  61 +done
  62 +
  63 +# Drop spurious distribution name bits
  64 +case $dist in
  65 + *-security)
  66 + dist=${dist%-security}
  67 + ;;
  68 + *)
  69 + ;;
  70 +esac
  71 +
  72 +builddist=$dist
  73 +case $dist in
  74 + unstable)
  75 + # We want to build unstable in a testing chroot
  76 + builddist=$current_testing
  77 + ;;
  78 + *)
  79 + ;;
  80 +esac
  81 +
  82 +dch -r -D $dist ""
  83 +
  84 +# create or update pbuilder chroot
  85 +basetgz=/var/cache/pbuilder/base-$builddist.tgz
  86 +if [ ! -f $basetgz ]
  87 +then
  88 + sudo pbuilder create --distribution $builddist --basetgz $basetgz --othermirror "deb http://security.debian.org/debian-security $builddist/updates main"
  89 +else
  90 + sudo pbuilder update --basetgz $basetgz
  91 +fi
  92 +
  93 +DEB_BUILD_OPTIONS="nocheck noddebs parallel=64" pdebuild --debbuildopts -B -- --basetgz "$basetgz"
... ...
firefox-patches/build-firefox 0 → 100755
  1 +++ a/firefox-patches/build-firefox
... ... @@ -0,0 +1,4 @@
  1 +#!/bin/sh
  2 +export srcdir=$(dirname $0)
  3 +export exp_srcpkg=firefox-esr
  4 +exec $srcdir/../build
... ...
firefox-patches/patches-52/F10 0 → 100644
  1 +++ a/firefox-patches/patches-52/F10
... ... @@ -0,0 +1,102 @@
  1 +# HG changeset patch
  2 +# User Colomban Wendling <cwendling@hypra.fr>
  3 +Bug 1166825 Do not focus the first item in the menu when open with F10 r=surkov
  4 +
  5 +This is consistent with other apps and toolkits (GTK, LibreOffice), and
  6 +gives blind people a better experience by providing a consistent
  7 +desktop experience, and consistent behavior of the right arrow key
  8 +regardless of the first focusable element.
  9 +
  10 +---
  11 + layout/xul/nsMenuBarListener.cpp | 2 +-
  12 + layout/xul/nsXULPopupManager.cpp | 17 ++++++++++++++++-
  13 + toolkit/content/tests/widgets/window_menubar.xul | 14 ++++++++------
  14 + 3 files changed, 25 insertions(+), 8 deletions(-)
  15 +
  16 +--- a/layout/xul/nsMenuBarListener.cpp
  17 ++++ b/layout/xul/nsMenuBarListener.cpp
  18 +@@ -325,7 +325,7 @@ nsMenuBarListener::KeyPress(nsIDOMEvent*
  19 + if (mMenuBarFrame->IsActive()) {
  20 + #ifdef MOZ_WIDGET_GTK
  21 + // In GTK, this also opens the first menu.
  22 +- mMenuBarFrame->GetCurrentMenuItem()->OpenMenu(true);
  23 ++ mMenuBarFrame->GetCurrentMenuItem()->OpenMenu(false);
  24 + #endif
  25 + aKeyEvent->StopPropagation();
  26 + aKeyEvent->PreventDefault();
  27 +--- a/layout/xul/nsXULPopupManager.cpp
  28 ++++ b/layout/xul/nsXULPopupManager.cpp
  29 +@@ -2173,6 +2173,21 @@ nsXULPopupManager::HandleKeyboardNavigat
  30 + aKeyCode <= nsIDOMKeyEvent::DOM_VK_DOWN, "Illegal key code");
  31 + theDirection = NS_DIRECTION_FROM_KEY_CODE(itemFrame, aKeyCode);
  32 +
  33 ++ bool selectFirstItem = true;
  34 ++#ifdef MOZ_WIDGET_GTK
  35 ++ nsMenuFrame* currentItem = nullptr;
  36 ++ if (item && mActiveMenuBar && NS_DIRECTION_IS_INLINE(theDirection)) {
  37 ++ currentItem = item->Frame()->GetCurrentMenuItem();
  38 ++ // If nothing is selected in the menu and we have a menubar, let it
  39 ++ // handle the movement not to steal focus from it.
  40 ++ if (!currentItem) {
  41 ++ item = nullptr;
  42 ++ }
  43 ++ }
  44 ++ // On menu change, only select first item if an item is already selected.
  45 ++ selectFirstItem = currentItem != nullptr;
  46 ++#endif
  47 ++
  48 + // if a popup is open, first check for navigation within the popup
  49 + if (item && HandleKeyboardNavigationInPopup(item, theDirection))
  50 + return true;
  51 +@@ -2185,7 +2200,7 @@ nsXULPopupManager::HandleKeyboardNavigat
  52 + nsMenuFrame* nextItem = (theDirection == eNavigationDirection_End) ?
  53 + GetNextMenuItem(mActiveMenuBar, currentMenu, false) :
  54 + GetPreviousMenuItem(mActiveMenuBar, currentMenu, false);
  55 +- mActiveMenuBar->ChangeMenuItem(nextItem, true, true);
  56 ++ mActiveMenuBar->ChangeMenuItem(nextItem, selectFirstItem, true);
  57 + return true;
  58 + }
  59 + else if (NS_DIRECTION_IS_BLOCK(theDirection)) {
  60 +--- a/toolkit/content/tests/widgets/window_menubar.xul
  61 ++++ b/toolkit/content/tests/widgets/window_menubar.xul
  62 +@@ -95,14 +95,14 @@ window.opener.SimpleTest.waitForFocus(fu
  63 + function pressF10Events()
  64 + {
  65 + return navigator.platform.indexOf("Linux") >= 0 ?
  66 +- [ "DOMMenuBarActive menubar", "DOMMenuItemActive filemenu", "popupshowing filepopup", "DOMMenuItemActive item1", "popupshown filepopup"] :
  67 ++ [ "DOMMenuBarActive menubar", "DOMMenuItemActive filemenu", "popupshowing filepopup", "popupshown filepopup"] :
  68 + [ "DOMMenuBarActive menubar", "DOMMenuItemActive filemenu" ];
  69 + }
  70 +
  71 + function closeAfterF10Events(extraInactive)
  72 + {
  73 + if (navigator.platform.indexOf("Linux") >= 0) {
  74 +- var events = [ "popuphiding filepopup", "popuphidden filepopup", "DOMMenuItemInactive item1",
  75 ++ var events = [ "popuphiding filepopup", "popuphidden filepopup",
  76 + "DOMMenuInactive filepopup", "DOMMenuBarInactive menubar",
  77 + "DOMMenuItemInactive filemenu" ];
  78 + if (extraInactive)
  79 +@@ -479,9 +479,9 @@ var popupTests = [
  80 + // "accelerator on active menubar" because menus opened from a
  81 + // shortcut key are fired asynchronously
  82 + "popuphiding filepopup", "popuphidden filepopup",
  83 +- "popupshowing helppopup", "DOMMenuItemInactive item1",
  84 +- "DOMMenuItemActive item2", "DOMMenuItemInactive item2",
  85 +- "DOMMenuInactive filepopup", "DOMMenuItemActive contents",
  86 ++ "popupshowing helppopup",
  87 ++ "DOMMenuItemActive item1", "DOMMenuItemInactive item1",
  88 ++ "DOMMenuInactive filepopup",
  89 + "popupshown helppopup" ] :
  90 + [ "popupshowing helppopup", "DOMMenuItemInactive filemenu",
  91 + "DOMMenuItemActive helpmenu",
  92 +@@ -499,7 +499,9 @@ var popupTests = [
  93 + // should not close because there is more than one item corresponding to
  94 + // that letter
  95 + testname: "menuitem with no accelerator",
  96 +- events: [ "DOMMenuItemInactive contents", "DOMMenuItemActive one" ],
  97 ++ events: (navigator.platform.indexOf("Linux") >= 0) ?
  98 ++ [ "DOMMenuItemActive one" ] :
  99 ++ [ "DOMMenuItemInactive contents", "DOMMenuItemActive one" ],
  100 + test: function() { sendChar("o"); },
  101 + result: function(testname) { checkOpen("helpmenu", testname); }
  102 + },
... ...
firefox-patches/patches-52/blur 0 → 100644
  1 +++ a/firefox-patches/patches-52/blur
... ... @@ -0,0 +1,65 @@
  1 +# HG changeset patch
  2 +# User Neil Deakin <neil@mozilla.com>
  3 +# Parent 76376169669fbc390d1cd297d4a3412f15f68461
  4 +Bug 422981, if the focused element is clear after focusing an element, still update the caret position. Additional fix when shift-tabbing from a caret position inside a focusable element to skip over that outer element.
  5 +
  6 +diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp
  7 +--- a/dom/base/nsFocusManager.cpp
  8 ++++ b/dom/base/nsFocusManager.cpp
  9 +@@ -2019,19 +2019,22 @@ nsFocusManager::Focus(nsPIDOMWindowOuter
  10 + }
  11 +
  12 + // update the caret visibility and position to match the newly focused
  13 + // element. However, don't update the position if this was a focus due to a
  14 + // mouse click as the selection code would already have moved the caret as
  15 + // needed. If this is a different document than was focused before, also
  16 + // update the caret's visibility. If this is the same document, the caret
  17 + // visibility should be the same as before so there is no need to update it.
  18 +- if (mFocusedContent == aContent)
  19 ++ // As a special case when there is no focused element (implying that the
  20 ++ // element was likely blurred during focus), still update the caret position.
  21 ++ if (!mFocusedContent || mFocusedContent == aContent) {
  22 + UpdateCaret(aFocusChanged && !(aFlags & FLAG_BYMOUSE), aIsNewDocument,
  23 +- mFocusedContent);
  24 ++ aContent);
  25 ++ }
  26 +
  27 + if (clearFirstFocusEvent)
  28 + mFirstFocusEvent = nullptr;
  29 + }
  30 +
  31 + class FocusBlurEvent : public Runnable
  32 + {
  33 + public:
  34 +@@ -2810,16 +2813,31 @@ nsFocusManager::DetermineElementToMoveFo
  35 + else {
  36 + // Otherwise, for content shells, start from the location of the caret.
  37 + nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
  38 + if (docShell && docShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
  39 + nsCOMPtr<nsIContent> endSelectionContent;
  40 + GetSelectionLocation(doc, presShell,
  41 + getter_AddRefs(startContent),
  42 + getter_AddRefs(endSelectionContent));
  43 ++
  44 ++ // If we are going backwards from the caret point, locate an enclosing
  45 ++ // focusable element and use that instead.
  46 ++ if (startContent && !forward && !forDocumentNavigation) {
  47 ++ nsIContent* focusableContent = startContent;
  48 ++ while (focusableContent) {
  49 ++ if (focusableContent->GetPrimaryFrame() &&
  50 ++ focusableContent->GetPrimaryFrame()->IsFocusable()) {
  51 ++ startContent = focusableContent;
  52 ++ break;
  53 ++ }
  54 ++ focusableContent = focusableContent->GetParent();
  55 ++ }
  56 ++ }
  57 ++
  58 + // If the selection is on the rootContent, then there is no selection
  59 + if (startContent == rootContent) {
  60 + startContent = nullptr;
  61 + }
  62 +
  63 + if (aType == MOVEFOCUS_CARET) {
  64 + // GetFocusInSelection finds a focusable link near the caret.
  65 + // If there is no start content though, don't do this to avoid
... ...
firefox-patches/patches-52/multibyte 0 → 100644
  1 +++ a/firefox-patches/patches-52/multibyte
... ... @@ -0,0 +1,257 @@
  1 +# HG changeset patch
  2 +# User Samuel Thibault <samuel.thibault@ens-lyon.org>
  3 +Bug 1346535 atk: Introduce U+FEFF characters to match AT-SPI offsets with DOM offsets r=surkov
  4 +
  5 +---
  6 + accessible/atk/nsMaiInterfaceText.cpp | 177 +++++++++++++++++++++++++++++++++-
  7 + xpcom/string/nsUTF8Utils.h | 17 +++
  8 + 2 files changed, 191 insertions(+), 3 deletions(-)
  9 +
  10 +--- a/accessible/atk/nsMaiInterfaceText.cpp
  11 ++++ b/accessible/atk/nsMaiInterfaceText.cpp
  12 +@@ -14,6 +14,7 @@
  13 + #include "nsIAccessibleTypes.h"
  14 + #include "nsIPersistentProperties2.h"
  15 + #include "nsISimpleEnumerator.h"
  16 ++#include "nsUTF8Utils.h"
  17 +
  18 + #include "mozilla/Likely.h"
  19 +
  20 +@@ -133,6 +134,139 @@ ConvertTexttoAsterisks(AccessibleWrap* a
  21 + }
  22 + }
  23 +
  24 ++// In order to properly get non-unicode16 values, change offsets to get one more
  25 ++// character on each end, so that ConvertUTF16toUTF8 can convert surrogates even
  26 ++// if the originally requested offsets fall between them.
  27 ++static void
  28 ++PrepareUTF16toUTF8(gint *aStartOffset, gint *aEndOffset,
  29 ++ bool *aStartShifted, bool *aEndShifted,
  30 ++ gint count)
  31 ++{
  32 ++ if (*aStartOffset > 0) {
  33 ++ (*aStartOffset)--;
  34 ++ *aStartShifted = true;
  35 ++ }
  36 ++
  37 ++ if (*aEndOffset != -1 && *aEndOffset < count) {
  38 ++ (*aEndOffset)++;
  39 ++ *aEndShifted = true;
  40 ++ }
  41 ++}
  42 ++
  43 ++// Remove the additional characters requested by PrepareUTF16toUTF8
  44 ++static bool
  45 ++FinishUTF16toUTF8(nsAutoCString &str, bool aStartShifted, bool aEndShifted)
  46 ++{
  47 ++ if (aStartShifted) {
  48 ++ // PrepareUTF16toUTF8 added a heading character
  49 ++
  50 ++ if (str.Length() == 0) {
  51 ++ // Odd, there should have been a character...
  52 ++ return false;
  53 ++ }
  54 ++
  55 ++ if ((int) str.Length() < UTF8traits::bytes(str[0])) {
  56 ++ // Odd, it should be complete...
  57 ++ return false;
  58 ++ }
  59 ++
  60 ++ // drop first character
  61 ++ str.Cut(0, UTF8traits::bytes(str[0]));
  62 ++ }
  63 ++
  64 ++ if (aEndShifted) {
  65 ++ // PrepareUTF16toUTF8 added a trailing character
  66 ++
  67 ++ int len = str.Length();
  68 ++ if (len == 0) {
  69 ++ // Odd, there should have been a character...
  70 ++ return false;
  71 ++ }
  72 ++
  73 ++ int trail;
  74 ++ // Find beginning of last character
  75 ++ for (trail = str.Length() - 1; trail >= 0; trail--) {
  76 ++ if (!UTF8traits::isInSeq(str[trail])) {
  77 ++ break;
  78 ++ }
  79 ++ }
  80 ++ if (trail < 0) {
  81 ++ // Odd, there should have been at least a whole character...
  82 ++ return false;
  83 ++ }
  84 ++ if (trail + UTF8traits::bytes(str[trail]) != len) {
  85 ++ // Odd, the character should be complete...
  86 ++ return false;
  87 ++ }
  88 ++
  89 ++ // Drop the last character
  90 ++ str.Truncate(trail);
  91 ++ }
  92 ++
  93 ++ return true;
  94 ++}
  95 ++
  96 ++// Add a BOM after each non-unicode16 character of str
  97 ++static nsAutoCString
  98 ++AddBOMs(nsAutoCString &str)
  99 ++{
  100 ++ uint32_t n;
  101 ++
  102 ++ // First compute how much room we will need
  103 ++ n = 0;
  104 ++ for (uint32_t i = 0; i < str.Length(); i++) {
  105 ++ if (UTF8traits::bytes(str[i]) >= 4) {
  106 ++ // non-unicode16 character, will add a BOM after it
  107 ++ n += 3;
  108 ++ }
  109 ++ n++;
  110 ++ }
  111 ++ if (n == str.Length()) {
  112 ++ // Nothing to do, just return original string
  113 ++ return str;
  114 ++ }
  115 ++
  116 ++ nsAutoCString ret;
  117 ++ uint32_t reti; // Index within ret
  118 ++
  119 ++ // Add BOMs after non-unicode16 characters
  120 ++ ret.Truncate(n);
  121 ++ reti = 0;
  122 ++ for (uint32_t i = 0; i < str.Length(); i++) {
  123 ++ uint32_t bytes = UTF8traits::bytes(str[i]);
  124 ++
  125 ++ if (bytes >= 4) {
  126 ++ // Non-unicode16 character, add a BOM after it.
  127 ++
  128 ++ if (bytes > (str.Length() - i)) {
  129 ++ // We don't have the whole sequence, copy what we have
  130 ++ for ( ; i < str.Length(); i++) {
  131 ++ ret.Replace(reti++, 1, str[i]);
  132 ++ }
  133 ++ ret.Truncate(reti);
  134 ++ return ret;
  135 ++ }
  136 ++
  137 ++ // Copy whole sequence.
  138 ++ for (uint32_t j = 0; j < bytes; j++) {
  139 ++ ret.Replace(reti++, 1, str[i + j]);
  140 ++ }
  141 ++ i += bytes-1;
  142 ++
  143 ++ // And add a BOM after it.
  144 ++ ret.Replace(reti++, 1, '\xEF');
  145 ++ ret.Replace(reti++, 1, '\xBB');
  146 ++ ret.Replace(reti++, 1, '\xBF');
  147 ++ } else {
  148 ++ // Unicode16, just copy the byte.
  149 ++ ret.Replace(reti++, 1, str[i]);
  150 ++ }
  151 ++ }
  152 ++ NS_ASSERTION(reti == n, "Bogus conversion!?");
  153 ++
  154 ++ return ret;
  155 ++}
  156 ++
  157 + extern "C" {
  158 +
  159 + static gchar*
  160 +@@ -140,22 +274,41 @@ getTextCB(AtkText *aText, gint aStartOff
  161 + {
  162 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
  163 + nsAutoString autoStr;
  164 ++ bool aStartShifted = false, aEndShifted = false;
  165 ++
  166 + if (accWrap) {
  167 + HyperTextAccessible* text = accWrap->AsHyperText();
  168 + if (!text || !text->IsTextRole())
  169 + return nullptr;
  170 +
  171 ++ PrepareUTF16toUTF8(&aStartOffset, &aEndOffset,
  172 ++ &aStartShifted, &aEndShifted,
  173 ++ text->IsDefunct() ? 0 :
  174 ++ static_cast<gint>(text->CharacterCount()));
  175 ++
  176 + text->TextSubstring(aStartOffset, aEndOffset, autoStr);
  177 +
  178 + ConvertTexttoAsterisks(accWrap, autoStr);
  179 + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
  180 ++
  181 ++ PrepareUTF16toUTF8(&aStartOffset, &aEndOffset,
  182 ++ &aStartShifted, &aEndShifted,
  183 ++ proxy->CharacterCount());
  184 ++
  185 + proxy->TextSubstring(aStartOffset, aEndOffset, autoStr);
  186 + }
  187 +
  188 + NS_ConvertUTF16toUTF8 cautoStr(autoStr);
  189 ++ if (!(cautoStr.get())) {
  190 ++ return nullptr;
  191 ++ }
  192 ++ nsAutoCString cautoStrBOM = AddBOMs(cautoStr);
  193 ++ if (!FinishUTF16toUTF8(cautoStrBOM, aStartShifted, aEndShifted)) {
  194 ++ return nullptr;
  195 ++ }
  196 +
  197 + //copy and return, libspi will free it.
  198 +- return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
  199 ++ return g_strdup(cautoStrBOM.get());
  200 + }
  201 +
  202 + static gchar*
  203 +@@ -222,8 +375,26 @@ getCharacterAtOffsetCB(AtkText* aText, g
  204 + return 0;
  205 + }
  206 +
  207 +- // char16_t is unsigned short in Mozilla, gnuichar is guint32 in glib.
  208 +- return static_cast<gunichar>(text->CharAt(aOffset));
  209 ++ // char16_t is unsigned short in Mozilla, gunichar is guint32 in glib.
  210 ++ gunichar character = static_cast<gunichar>(text->CharAt(aOffset));
  211 ++
  212 ++ if (NS_IS_LOW_SURROGATE(character)) {
  213 ++ // Trailing surrogate, return BOM instead.
  214 ++ return 0xFEFF;
  215 ++ }
  216 ++
  217 ++ if (NS_IS_HIGH_SURROGATE(character)) {
  218 ++ // Heading surrogate, get the trailing surrogate and combine them.
  219 ++ gunichar characterLow = static_cast<gunichar>(text->CharAt(aOffset + 1));
  220 ++
  221 ++ if (!NS_IS_LOW_SURROGATE(characterLow)) {
  222 ++ // It should have been a trailing surrogate... Flag the error.
  223 ++ return 0xFFFD;
  224 ++ }
  225 ++ return SURROGATE_TO_UCS4(character, characterLow);
  226 ++ }
  227 ++
  228 ++ return character;
  229 + }
  230 +
  231 + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
  232 +--- a/xpcom/string/nsUTF8Utils.h
  233 ++++ b/xpcom/string/nsUTF8Utils.h
  234 +@@ -54,6 +54,23 @@ public:
  235 + {
  236 + return (aChar & 0xFE) == 0xFC;
  237 + }
  238 ++ static int bytes(char aChar)
  239 ++ {
  240 ++ if (isASCII(aChar))
  241 ++ return 1;
  242 ++ if (is2byte(aChar))
  243 ++ return 2;
  244 ++ if (is3byte(aChar))
  245 ++ return 3;
  246 ++ if (is4byte(aChar))
  247 ++ return 4;
  248 ++ if (is5byte(aChar))
  249 ++ return 5;
  250 ++ if (is6byte(aChar))
  251 ++ return 6;
  252 ++ // Not supposed to be used for in-sequence, but return 1
  253 ++ return 1;
  254 ++ }
  255 + };
  256 +
  257 + /**
... ...
firefox-patches/patches-52/scroll 0 → 100644
  1 +++ a/firefox-patches/patches-52/scroll
... ... @@ -0,0 +1,29 @@
  1 +On accessibility SetSelectionRange, scroll the selection into view
  2 +
  3 +When a blind user reads around in a page, he wants firefox to keep
  4 +showing on the screen the current caret, so that sighted colleagues can
  5 +see what he is moving to. If the caret goes off what is visible, we
  6 +need to scroll to get the selection into view.
  7 +
  8 +For normal keypresses this already works,
  9 +nsPhysicalSelectMoveScrollCommand::DoCommand calls
  10 +nsFrameSelection::MoveCaret which calls ScrollIntoView, before DoCommand
  11 +calls AdjustFocusAfterCaretMove(). HyperTextAccessible needs to do the
  12 +same to get the same behavior.
  13 +
  14 +--- a/accessible/generic/HyperTextAccessible.cpp
  15 ++++ b/accessible/generic/HyperTextAccessible.cpp
  16 +@@ -1358,6 +1358,13 @@ HyperTextAccessible::SetSelectionRange(i
  17 + domSel->RemoveRange(domSel->GetRangeAt(idx));
  18 + SetSelectionBoundsAt(0, aStartPos, aEndPos);
  19 +
  20 ++ // Make sure it is visible
  21 ++ domSel->ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION,
  22 ++ nsIPresShell::ScrollAxis(),
  23 ++ nsIPresShell::ScrollAxis(),
  24 ++ dom::Selection::SCROLL_FOR_CARET_MOVE |
  25 ++ dom::Selection::SCROLL_OVERFLOW_HIDDEN);
  26 ++
  27 + // When selection is done, move the focus to the selection if accessible is
  28 + // not focusable. That happens when selection is set within hypertext
  29 + // accessible.
... ...
firefox-patches/patches-52/scrollto 0 → 100644
  1 +++ a/firefox-patches/patches-52/scrollto
... ... @@ -0,0 +1,177 @@
  1 +# HG changeset patch
  2 +# User Samuel Thibault <samuel.thibault@ens-lyon.org>
  3 +# Date 1525269333 -7200
  4 +# Wed May 02 15:55:33 2018 +0200
  5 +# Branch scrollto
  6 +# Node ID 66cabb17979cb117aa0d7e1927f8b0c0642c2a0f
  7 +# Parent 87bd488c19f620d726b8363d47c8a320bae9bb7c
  8 +Bug 1458548 atk: Implement scrollto ATK API r=surkov
  9 +
  10 +Index: firefox-esr-52.8.0esr-1~deb8u1/accessible/atk/nsMaiInterfaceComponent.cpp
  11 +===================================================================
  12 +--- firefox-esr-52.8.0esr-1~deb8u1.orig/accessible/atk/nsMaiInterfaceComponent.cpp
  13 ++++ firefox-esr-52.8.0esr-1~deb8u1/accessible/atk/nsMaiInterfaceComponent.cpp
  14 +@@ -6,6 +6,7 @@
  15 +
  16 + #include "InterfaceInitFuncs.h"
  17 +
  18 ++#include "Accessible-inl.h"
  19 + #include "AccessibleWrap.h"
  20 + #include "nsAccUtils.h"
  21 + #include "nsCoreUtils.h"
  22 +@@ -51,6 +52,46 @@ grabFocusCB(AtkComponent* aComponent)
  23 +
  24 + return FALSE;
  25 + }
  26 ++
  27 ++// ScrollType is compatible
  28 ++static gboolean
  29 ++scrollToCB(AtkComponent* aComponent, AtkScrollType type)
  30 ++{
  31 ++ AtkObject* atkObject = ATK_OBJECT(aComponent);
  32 ++ AccessibleWrap* accWrap = GetAccessibleWrap(atkObject);
  33 ++ if (accWrap) {
  34 ++ accWrap->ScrollTo(type);
  35 ++ return TRUE;
  36 ++ }
  37 ++
  38 ++ ProxyAccessible* proxy = GetProxy(atkObject);
  39 ++ if (proxy) {
  40 ++ proxy->ScrollTo(type);
  41 ++ return TRUE;
  42 ++ }
  43 ++
  44 ++ return FALSE;
  45 ++}
  46 ++
  47 ++// CoordType is compatible
  48 ++static gboolean
  49 ++scrollToPointCB(AtkComponent* aComponent, AtkCoordType coords, gint x, gint y)
  50 ++{
  51 ++ AtkObject* atkObject = ATK_OBJECT(aComponent);
  52 ++ AccessibleWrap* accWrap = GetAccessibleWrap(atkObject);
  53 ++ if (accWrap) {
  54 ++ accWrap->ScrollToPoint(coords, x, y);
  55 ++ return TRUE;
  56 ++ }
  57 ++
  58 ++ ProxyAccessible* proxy = GetProxy(atkObject);
  59 ++ if (proxy) {
  60 ++ proxy->ScrollToPoint(coords, x, y);
  61 ++ return TRUE;
  62 ++ }
  63 ++
  64 ++ return FALSE;
  65 ++}
  66 + }
  67 +
  68 + AtkObject*
  69 +@@ -148,4 +189,8 @@ componentInterfaceInitCB(AtkComponentIfa
  70 + aIface->ref_accessible_at_point = refAccessibleAtPointCB;
  71 + aIface->get_extents = getExtentsCB;
  72 + aIface->grab_focus = grabFocusCB;
  73 ++ if (IsAtkVersionAtLeast(2, 30)) {
  74 ++ aIface->scroll_to = scrollToCB;
  75 ++ aIface->scroll_to_point = scrollToPointCB;
  76 ++ }
  77 + }
  78 +Index: firefox-esr-52.8.0esr-1~deb8u1/other-licenses/atk-1.0/atk/atkcomponent.h
  79 +===================================================================
  80 +--- firefox-esr-52.8.0esr-1~deb8u1.orig/other-licenses/atk-1.0/atk/atkcomponent.h
  81 ++++ firefox-esr-52.8.0esr-1~deb8u1/other-licenses/atk-1.0/atk/atkcomponent.h
  82 +@@ -27,6 +27,36 @@
  83 + extern "C" {
  84 + #endif /* __cplusplus */
  85 +
  86 ++/**
  87 ++ *AtkScrollType:
  88 ++ *@ATK_SCROLL_TOP_LEFT: Scroll the object vertically and horizontally to the top
  89 ++ *left corner of the window.
  90 ++ *@ATK_SCROLL_BOTTOM_RIGHT: Scroll the object vertically and horizontally to the
  91 ++ *bottom right corner of the window.
  92 ++ *@ATK_SCROLL_TOP_EDGE: Scroll the object vertically to the top edge of the
  93 ++ window.
  94 ++ *@ATK_SCROLL_BOTTOM_EDGE: Scroll the object vertically to the bottom edge of
  95 ++ *the window.
  96 ++ *@ATK_SCROLL_LEFT_EDGE: Scroll the object vertically and horizontally to the
  97 ++ *left edge of the window.
  98 ++ *@ATK_SCROLL_RIGHT_EDGE: Scroll the object vertically and horizontally to the
  99 ++ *right edge of the window.
  100 ++ *@ATK_SCROLL_ANYWHERE: Scroll the object vertically and horizontally so that
  101 ++ *as much as possible of the object becomes visible. The exact placement is
  102 ++ *determined by the application.
  103 ++ *
  104 ++ * Specifies where an object should be placed on the screen when using scroll_to.
  105 ++ **/
  106 ++typedef enum {
  107 ++ ATK_SCROLL_TOP_LEFT,
  108 ++ ATK_SCROLL_BOTTOM_RIGHT,
  109 ++ ATK_SCROLL_TOP_EDGE,
  110 ++ ATK_SCROLL_BOTTOM_EDGE,
  111 ++ ATK_SCROLL_LEFT_EDGE,
  112 ++ ATK_SCROLL_RIGHT_EDGE,
  113 ++ ATK_SCROLL_ANYWHERE
  114 ++} AtkScrollType;
  115 ++
  116 + /*
  117 + * The AtkComponent interface should be supported by any object that is
  118 + * rendered on the screen. The interface provides the standard mechanism
  119 +@@ -115,6 +145,18 @@ struct _AtkComponentIface
  120 + void (* bounds_changed) (AtkComponent *component,
  121 + AtkRectangle *bounds);
  122 + gdouble (* get_alpha) (AtkComponent *component);
  123 ++
  124 ++ /*
  125 ++ * Scrolls this object so it becomes visible on the screen.
  126 ++ * Since ATK 2.30
  127 ++ */
  128 ++ gboolean (*scroll_to) (AtkComponent *component,
  129 ++ AtkScrollType type);
  130 ++
  131 ++ gboolean (*scroll_to_point) (AtkComponent *component,
  132 ++ AtkCoordType coords,
  133 ++ gint x,
  134 ++ gint y);
  135 + };
  136 +
  137 + GType atk_component_get_type (void);
  138 +@@ -163,6 +205,14 @@ gboolean atk_component_set_
  139 + gint width,
  140 + gint height);
  141 + gdouble atk_component_get_alpha (AtkComponent *component);
  142 ++gboolean atk_component_scroll_to (AtkComponent *component,
  143 ++ AtkScrollType type);
  144 ++
  145 ++gboolean atk_component_scroll_to_point (AtkComponent *component,
  146 ++ AtkCoordType coords,
  147 ++ gint x,
  148 ++ gint y);
  149 ++
  150 + #ifdef __cplusplus
  151 + }
  152 + #endif /* __cplusplus */
  153 +Index: firefox-esr-52.8.0esr-1~deb8u1/other-licenses/atk-1.0/atk/atkutil.h
  154 +===================================================================
  155 +--- firefox-esr-52.8.0esr-1~deb8u1.orig/other-licenses/atk-1.0/atk/atkutil.h
  156 ++++ firefox-esr-52.8.0esr-1~deb8u1/other-licenses/atk-1.0/atk/atkutil.h
  157 +@@ -153,15 +153,18 @@ GType atk_util_get_type (void);
  158 + /**
  159 + *AtkCoordType:
  160 + *@ATK_XY_SCREEN: specifies xy coordinates relative to the screen
  161 +- *@ATK_XY_WINDOW: specifies xy coordinates relative to the widget's
  162 ++ *@ATK_XY_WINDOW: specifies xy coordinates relative to the widget's
  163 + * top-level window
  164 ++ *@ATK_XY_PARENT: specifies xy coordinates relative to the widget's
  165 ++ * immediate parent.
  166 + *
  167 + *Specifies how xy coordinates are to be interpreted. Used by functions such
  168 + *as atk_component_get_position() and atk_text_get_character_extents()
  169 + **/
  170 + typedef enum {
  171 + ATK_XY_SCREEN,
  172 +- ATK_XY_WINDOW
  173 ++ ATK_XY_WINDOW,
  174 ++ ATK_XY_PARENT
  175 + }AtkCoordType;
  176 +
  177 + /*
... ...
firefox-patches/patches-52/setcaret 0 → 100644
  1 +++ a/firefox-patches/patches-52/setcaret
... ... @@ -0,0 +1,33 @@
  1 +# HG changeset patch
  2 +# User Samuel Thibault <samuel.thibault@ens-lyon.org>
  3 +# Date 1533116635 -7200
  4 +# Wed Aug 01 11:43:55 2018 +0200
  5 +# Node ID 4e181e0f33dea9c80a66b1528dd367a02d5d04da
  6 +# Parent 0d72c7996d60a7c07e35c5f90d78b02a47d17460
  7 +Bug 1478964 HyperTextAccessible: Make TransformOffset return 0 when offset is at the beginning r=asurkov
  8 +
  9 +diff --git a/accessible/generic/HyperTextAccessible.cpp b/accessible/generic/HyperTextAccessible.cpp
  10 +--- a/accessible/generic/HyperTextAccessible.cpp
  11 ++++ b/accessible/generic/HyperTextAccessible.cpp
  12 +@@ -294,16 +294,21 @@ HyperTextAccessible::DOMPointToOffset(ns
  13 +
  14 + uint32_t
  15 + HyperTextAccessible::TransformOffset(Accessible* aDescendant,
  16 + uint32_t aOffset, bool aIsEndOffset) const
  17 + {
  18 + // From the descendant, go up and get the immediate child of this hypertext.
  19 + uint32_t offset = aOffset;
  20 + Accessible* descendant = aDescendant;
  21 ++ if (descendant == this) {
  22 ++ // Children are further than this offset
  23 ++ // E.g. when looking at offset 0 (the bullet) in a list element
  24 ++ return 0;
  25 ++ }
  26 + while (descendant) {
  27 + Accessible* parent = descendant->Parent();
  28 + if (parent == this)
  29 + return GetChildOffset(descendant) + offset;
  30 +
  31 + // This offset no longer applies because the passed-in text object is not
  32 + // a child of the hypertext. This happens when there are nested hypertexts,
  33 + // e.g. <div>abc<h1>def</h1>ghi</div>. Thus we need to adjust the offset
... ...
firefox-patches/patches-52/tabswitch4 0 → 100644
  1 +++ a/firefox-patches/patches-52/tabswitch4
... ... @@ -0,0 +1,128 @@
  1 +# HG changeset patch
  2 +# User Samuel Thibault <samuel.thibault@ens-lyon.org>
  3 +Bug 1260598 Make document events wait for chrome content insertion events r=surkov
  4 +
  5 +When switching from a tab to another, accessibility layers needs to get
  6 +events about the tab switch before events about the newly-focused
  7 +element of the document.
  8 +
  9 +This changeset does it so by first making IsUpdatePending() not only
  10 +watch for the document's pending updates, but also its parent's pending
  11 +updates, so that the document doesn't process focus events immediately,
  12 +but queue them.
  13 +
  14 +Then, WillRefresh for the document should not process events until its
  15 +parent chrome has finished processing its content insertion events
  16 +(corresponding to the tab switch).
  17 +
  18 +Eventually, ScheduleContentInsertion can not afford leaving an empty
  19 +array of notifications and not a schedule processing any more.
  20 +(was introduced by c2aeece5eb10 'Bug 1242989 - keep content insertions
  21 +in a hash')
  22 +
  23 +Index: firefox-esr-52.5.2esr-1~deb8u1/accessible/base/NotificationController.cpp
  24 +===================================================================
  25 +--- firefox-esr-52.5.2esr-1~deb8u1.orig/accessible/base/NotificationController.cpp
  26 ++++ firefox-esr-52.5.2esr-1~deb8u1/accessible/base/NotificationController.cpp
  27 +@@ -417,8 +417,15 @@ NotificationController::ScheduleContentI
  28 + nsIContent* aStartChildNode,
  29 + nsIContent* aEndChildNode)
  30 + {
  31 +- nsTArray<nsCOMPtr<nsIContent>>* list =
  32 +- mContentInsertions.LookupOrAdd(aContainer);
  33 ++ nsTArray<nsCOMPtr<nsIContent>>* list;
  34 ++ nsTArray<nsCOMPtr<nsIContent>>* existingList =
  35 ++ mContentInsertions.Get(aContainer);
  36 ++
  37 ++ if (existingList) {
  38 ++ list = existingList;
  39 ++ } else {
  40 ++ list = new nsTArray<nsCOMPtr<nsIContent>>;
  41 ++ }
  42 +
  43 + bool needsProcessing = false;
  44 + nsIContent* node = aStartChildNode;
  45 +@@ -433,6 +440,18 @@ NotificationController::ScheduleContentI
  46 + node = node->GetNextSibling();
  47 + }
  48 +
  49 ++ // Note: we avoid adding an empty array to the hash, because below we will not
  50 ++ // schedule processing (as an optimization), and leaving an empty array in the
  51 ++ // hash would let children think we have work to do, but we would actually not
  52 ++ // process this empty array in the close future.
  53 ++ if (!existingList) {
  54 ++ if (list->Length() == 0) {
  55 ++ delete list;
  56 ++ } else {
  57 ++ mContentInsertions.Put(aContainer, list);
  58 ++ }
  59 ++ }
  60 ++
  61 + if (needsProcessing) {
  62 + ScheduleProcessing();
  63 + }
  64 +@@ -457,11 +476,31 @@ NotificationController::IsUpdatePending(
  65 + {
  66 + return mPresShell->IsLayoutFlushObserver() ||
  67 + mObservingState == eRefreshProcessingForUpdate ||
  68 ++ WaitingForParent() ||
  69 + mContentInsertions.Count() != 0 || mNotifications.Length() != 0 ||
  70 + mTextHash.Count() != 0 ||
  71 + !mDocument->HasLoadState(DocAccessible::eTreeConstructed);
  72 + }
  73 +
  74 ++bool
  75 ++NotificationController::WaitingForParent()
  76 ++{
  77 ++ DocAccessible* parentdoc = mDocument->ParentDocument();
  78 ++ if (!parentdoc) {
  79 ++ return false;
  80 ++ }
  81 ++
  82 ++ NotificationController* parent = parentdoc->mNotificationController;
  83 ++ if (!parent || parent == this) {
  84 ++ // Do not wait for nothing or ourselves
  85 ++ return false;
  86 ++ }
  87 ++
  88 ++ // Wait for parent's notifications processing
  89 ++ return parent->mContentInsertions.Count() != 0 ||
  90 ++ parent->mNotifications.Length() != 0;
  91 ++}
  92 ++
  93 + void
  94 + NotificationController::ProcessMutationEvents()
  95 + {
  96 +@@ -604,6 +643,15 @@ NotificationController::WillRefresh(mozi
  97 + mObservingState == eRefreshProcessingForUpdate)
  98 + return;
  99 +
  100 ++ // Wait for parent's notifications, to get proper ordering between e.g. tab
  101 ++ // event and content event.
  102 ++ if (WaitingForParent()) {
  103 ++ mDocument->ParentDocument()->mNotificationController->WillRefresh(aTime);
  104 ++ if (!mDocument) {
  105 ++ return;
  106 ++ }
  107 ++ }
  108 ++
  109 + // Any generic notifications should be queued if we're processing content
  110 + // insertions or generic notifications.
  111 + mObservingState = eRefreshProcessingForUpdate;
  112 +Index: firefox-esr-52.5.2esr-1~deb8u1/accessible/base/NotificationController.h
  113 +===================================================================
  114 +--- firefox-esr-52.5.2esr-1~deb8u1.orig/accessible/base/NotificationController.h
  115 ++++ firefox-esr-52.5.2esr-1~deb8u1/accessible/base/NotificationController.h
  116 +@@ -274,6 +274,12 @@ protected:
  117 + */
  118 + bool IsUpdatePending();
  119 +
  120 ++ /**
  121 ++ * Return true if we should wait for processing from the parent before we can
  122 ++ * process our own queue.
  123 ++ */
  124 ++ bool WaitingForParent();
  125 ++
  126 + private:
  127 + NotificationController(const NotificationController&);
  128 + NotificationController& operator = (const NotificationController&);
... ...
firefox-patches/patches-52/twisties 0 → 100644
  1 +++ a/firefox-patches/patches-52/twisties
... ... @@ -0,0 +1,110 @@
  1 +Bug 1376756 gtk: while drawing nsTreeBodyFrame, fetch current row attributes for proper style rendering r=karlt
  2 +
  3 +---
  4 + layout/xul/tree/nsTreeBodyFrame.h | 7 +++++++
  5 + widget/gtk/gtk2drawing.c | 5 ++++-
  6 + widget/gtk/gtk3drawing.cpp | 7 +++++++
  7 + widget/gtk/gtkdrawing.h | 1 +
  8 + widget/gtk/nsNativeThemeGTK.cpp | 11 +++++++++++
  9 + 5 files changed, 30 insertions(+), 1 deletion(-)
  10 +
  11 +Index: firefox-esr-52.8.1esr-1~deb8u1/widget/gtk/gtk3drawing.cpp
  12 +===================================================================
  13 +--- firefox-esr-52.8.1esr-1~deb8u1.orig/widget/gtk/gtk3drawing.cpp
  14 ++++ firefox-esr-52.8.1esr-1~deb8u1/widget/gtk/gtk3drawing.cpp
  15 +@@ -993,6 +993,13 @@ moz_gtk_treeview_expander_paint(cairo_t
  16 + GtkStateFlags state_flags = state->disabled ? GTK_STATE_FLAG_INSENSITIVE :
  17 + GTK_STATE_FLAG_NORMAL;
  18 +
  19 ++ if (state->inHover)
  20 ++ state_flags =
  21 ++ static_cast<GtkStateFlags>(state_flags|GTK_STATE_FLAG_PRELIGHT);
  22 ++ if (state->selected)
  23 ++ state_flags =
  24 ++ static_cast<GtkStateFlags>(state_flags|GTK_STATE_FLAG_SELECTED);
  25 ++
  26 + /* GTK_STATE_FLAG_ACTIVE controls expanded/colapsed state rendering
  27 + * in gtk_render_expander()
  28 + */
  29 +Index: firefox-esr-52.8.1esr-1~deb8u1/widget/gtk/nsNativeThemeGTK.cpp
  30 +===================================================================
  31 +--- firefox-esr-52.8.1esr-1~deb8u1.orig/widget/gtk/nsNativeThemeGTK.cpp
  32 ++++ firefox-esr-52.8.1esr-1~deb8u1/widget/gtk/nsNativeThemeGTK.cpp
  33 +@@ -19,6 +19,7 @@
  34 + #include "nsGfxCIID.h"
  35 + #include "nsTransform2D.h"
  36 + #include "nsMenuFrame.h"
  37 ++#include "tree/nsTreeBodyFrame.h"
  38 + #include "prlink.h"
  39 + #include "nsIDOMHTMLInputElement.h"
  40 + #include "nsRenderingContext.h"
  41 +@@ -246,6 +247,7 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
  42 + aState->disabled = IsDisabled(aFrame, eventState) || IsReadOnly(aFrame);
  43 + aState->active = eventState.HasState(NS_EVENT_STATE_ACTIVE);
  44 + aState->focused = eventState.HasState(NS_EVENT_STATE_FOCUS);
  45 ++ aState->selected = FALSE;
  46 + aState->inHover = eventState.HasState(NS_EVENT_STATE_HOVER);
  47 + aState->isDefault = IsDefaultButton(aFrame);
  48 + aState->canDefault = FALSE; // XXX fix me
  49 +@@ -267,6 +269,15 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
  50 + aWidgetType == NS_THEME_MENULIST ||
  51 + aWidgetType == NS_THEME_MENULIST_BUTTON) {
  52 + aState->active &= aState->inHover;
  53 ++ } else if (aWidgetType == NS_THEME_TREETWISTY ||
  54 ++ aWidgetType == NS_THEME_TREETWISTYOPEN) {
  55 ++ nsTreeBodyFrame *treeBodyFrame = do_QueryFrame(aFrame);
  56 ++ if (treeBodyFrame) {
  57 ++ const AtomArray& atoms =
  58 ++ treeBodyFrame->GetPropertyArrayForCurrentDrawingItem();
  59 ++ aState->selected = atoms.Contains(nsGkAtoms::selected);
  60 ++ aState->inHover = atoms.Contains(nsGkAtoms::hover);
  61 ++ }
  62 + }
  63 +
  64 + if (IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) {
  65 +Index: firefox-esr-52.8.1esr-1~deb8u1/layout/xul/tree/nsTreeBodyFrame.h
  66 +===================================================================
  67 +--- firefox-esr-52.8.1esr-1~deb8u1.orig/layout/xul/tree/nsTreeBodyFrame.h
  68 ++++ firefox-esr-52.8.1esr-1~deb8u1/layout/xul/tree/nsTreeBodyFrame.h
  69 +@@ -205,6 +205,13 @@ public:
  70 + bool GetVerticalOverflow() const { return mVerticalOverflow; }
  71 + bool GetHorizontalOverflow() const {return mHorizontalOverflow; }
  72 +
  73 ++ // This returns the property array where atoms are stored for style during
  74 ++ // draw, whether the row currently being drawn is selected, hovered, etc.
  75 ++ const AtomArray& GetPropertyArrayForCurrentDrawingItem()
  76 ++ {
  77 ++ return mScratchArray;
  78 ++ }
  79 ++
  80 + protected:
  81 + friend class nsOverflowChecker;
  82 +
  83 +Index: firefox-esr-52.8.1esr-1~deb8u1/widget/gtk/gtkdrawing.h
  84 +===================================================================
  85 +--- firefox-esr-52.8.1esr-1~deb8u1.orig/widget/gtk/gtkdrawing.h
  86 ++++ firefox-esr-52.8.1esr-1~deb8u1/widget/gtk/gtkdrawing.h
  87 +@@ -28,6 +28,7 @@ extern "C" {
  88 + typedef struct {
  89 + guint8 active;
  90 + guint8 focused;
  91 ++ guint8 selected;
  92 + guint8 inHover;
  93 + guint8 disabled;
  94 + guint8 isDefault;
  95 +Index: firefox-esr-52.8.1esr-1~deb8u1/widget/gtk/gtk2drawing.c
  96 +===================================================================
  97 +--- firefox-esr-52.8.1esr-1~deb8u1.orig/widget/gtk/gtk2drawing.c
  98 ++++ firefox-esr-52.8.1esr-1~deb8u1/widget/gtk/gtk2drawing.c
  99 +@@ -1794,7 +1794,10 @@ moz_gtk_treeview_expander_paint(GdkDrawa
  100 +
  101 + /* Because the frame we get is of the entire treeview, we can't get the precise
  102 + * event state of one expander, thus rendering hover and active feedback useless. */
  103 +- state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
  104 ++ state_type = state->disabled ? GTK_STATE_INSENSITIVE :
  105 ++ state->inHover ? GTK_STATE_PRELIGHT :
  106 ++ state->selected ? GTK_STATE_SELECTED :
  107 ++ GTK_STATE_NORMAL;
  108