Merge mozilla-central to mozilla-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 20 Jul 2016 16:56:03 +0200
changeset 330980 f90a9f8af37c202842f5d9c5b2928004124ab5e1
parent 330979 efb4af0a5b7550d9d2efbb126df62c75a3082be2 (current diff)
parent 330892 d224fc999cb6accb208af0a105f14433375e2e77 (diff)
child 330981 311e127edfff11350cfa5beb2cee1310cd3d1aa7
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone50.0a1
Merge mozilla-central to mozilla-inbound
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -249,17 +249,16 @@ MediaDecoderStateMachine::MediaDecoderSt
   mAmpleAudioThresholdUsecs(detail::AMPLE_AUDIO_USECS),
   mQuickBufferingLowDataThresholdUsecs(detail::QUICK_BUFFERING_LOW_DATA_USECS),
   mIsAudioPrerolling(false),
   mIsVideoPrerolling(false),
   mAudioCaptured(false),
   INIT_WATCHABLE(mAudioCompleted, false),
   INIT_WATCHABLE(mVideoCompleted, false),
   mNotifyMetadataBeforeFirstFrame(false),
-  mDispatchedEventToDecode(false),
   mQuickBuffering(false),
   mMinimizePreroll(false),
   mDecodeThreadWaiting(false),
   mDecodingFirstFrame(true),
   mSentLoadedMetadataEvent(false),
   mSentFirstFrameLoadedEvent(false),
   mSentPlaybackEndedEvent(false),
   mVideoDecodeSuspended(false),
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -865,21 +865,16 @@ private:
   // Flag whether we notify metadata before decoding the first frame or after.
   //
   // Note that the odd semantics here are designed to replicate the current
   // behavior where we notify the decoder each time we come out of dormant, but
   // send suppressed event visibility for those cases. This code can probably be
   // simplified.
   bool mNotifyMetadataBeforeFirstFrame;
 
-  // True if we've dispatched an event to the decode task queue to call
-  // DecodeThreadRun(). We use this flag to prevent us from dispatching
-  // unnecessary runnables, since the decode thread runs in a loop.
-  bool mDispatchedEventToDecode;
-
   // If this is true while we're in buffering mode, we can exit early,
   // as it's likely we may be able to playback. This happens when we enter
   // buffering mode soon after the decode starts, because the decode-ahead
   // ran fast enough to exhaust all data while the download is starting up.
   // Synchronised via decoder monitor.
   bool mQuickBuffering;
 
   // True if we should not decode/preroll unnecessary samples, unless we're
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -3568,17 +3568,18 @@ StyleClipBasicShapeToCSSArray(const nsSt
       functionArray->Item(functionArray->Count() - 1).
                        SetArrayValue(radiusArray, eCSSUnit_Array);
       break;
     }
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown shape type");
       return false;
   }
-  aResult->Item(1).SetIntValue(aClipPath.GetSizingBox(), eCSSUnit_Enumerated);
+  aResult->Item(1).SetIntValue(uint8_t(aClipPath.GetSizingBox()),
+                               eCSSUnit_Enumerated);
   return true;
 }
 
 bool
 StyleAnimationValue::ExtractComputedValue(nsCSSProperty aProperty,
                                           nsStyleContext* aStyleContext,
                                           StyleAnimationValue& aComputedValue)
 {
@@ -3958,17 +3959,18 @@ StyleAnimationValue::ExtractComputedValu
               new mozilla::css::URLValue(clipPath.GetURL(),
                                          uriAsStringBuffer,
                                          doc->GetDocumentURI(),
                                          doc->NodePrincipal());
             auto result = MakeUnique<nsCSSValue>();
             result->SetURLValue(url);
             aComputedValue.SetAndAdoptCSSValueValue(result.release(), eUnit_URL);
           } else if (type == NS_STYLE_CLIP_PATH_BOX) {
-            aComputedValue.SetIntValue(clipPath.GetSizingBox(), eUnit_Enumerated);
+            aComputedValue.SetIntValue(uint8_t(clipPath.GetSizingBox()),
+                                       eUnit_Enumerated);
           } else if (type == NS_STYLE_CLIP_PATH_SHAPE) {
             RefPtr<nsCSSValue::Array> result = nsCSSValue::Array::Create(2);
             if (!StyleClipBasicShapeToCSSArray(clipPath, result)) {
               return false;
             }
             aComputedValue.SetCSSValueArrayValue(result, eUnit_Shape);
 
           } else {
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -2295,23 +2295,23 @@ const KTableEntry nsCSSProps::kDominantB
 
 const KTableEntry nsCSSProps::kFillRuleKTable[] = {
   { eCSSKeyword_nonzero, NS_STYLE_FILL_RULE_NONZERO },
   { eCSSKeyword_evenodd, NS_STYLE_FILL_RULE_EVENODD },
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kClipShapeSizingKTable[] = {
-  { eCSSKeyword_content_box,   NS_STYLE_CLIP_SHAPE_SIZING_CONTENT },
-  { eCSSKeyword_padding_box,   NS_STYLE_CLIP_SHAPE_SIZING_PADDING },
-  { eCSSKeyword_border_box,    NS_STYLE_CLIP_SHAPE_SIZING_BORDER },
-  { eCSSKeyword_margin_box,    NS_STYLE_CLIP_SHAPE_SIZING_MARGIN },
-  { eCSSKeyword_fill_box,      NS_STYLE_CLIP_SHAPE_SIZING_FILL },
-  { eCSSKeyword_stroke_box,    NS_STYLE_CLIP_SHAPE_SIZING_STROKE },
-  { eCSSKeyword_view_box,      NS_STYLE_CLIP_SHAPE_SIZING_VIEW },
+  { eCSSKeyword_content_box,   uint8_t(StyleClipShapeSizing::Content) },
+  { eCSSKeyword_padding_box,   uint8_t(StyleClipShapeSizing::Padding) },
+  { eCSSKeyword_border_box,    uint8_t(StyleClipShapeSizing::Border) },
+  { eCSSKeyword_margin_box,    uint8_t(StyleClipShapeSizing::Margin) },
+  { eCSSKeyword_fill_box,      uint8_t(StyleClipShapeSizing::Fill) },
+  { eCSSKeyword_stroke_box,    uint8_t(StyleClipShapeSizing::Stroke) },
+  { eCSSKeyword_view_box,      uint8_t(StyleClipShapeSizing::View) },
   { eCSSKeyword_UNKNOWN,       -1 }
 };
 
 const KTableEntry nsCSSProps::kShapeRadiusKTable[] = {
   { eCSSKeyword_closest_side, NS_RADIUS_CLOSEST_SIDE },
   { eCSSKeyword_farthest_side, NS_RADIUS_FARTHEST_SIDE },
   { eCSSKeyword_UNKNOWN, -1 }
 };
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -5970,31 +5970,32 @@ nsComputedDOMStyle::CreatePrimitiveValue
   shapeFunctionString.Append(')');
   RefPtr<nsROCSSPrimitiveValue> functionValue = new nsROCSSPrimitiveValue;
   functionValue->SetString(shapeFunctionString);
   return functionValue.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
-  const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox)
+  const nsStyleBasicShape* aStyleBasicShape,
+  mozilla::StyleClipShapeSizing aSizingBox)
 {
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   if (aStyleBasicShape) {
     valueList->AppendCSSValue(
       CreatePrimitiveValueForBasicShape(aStyleBasicShape));
   }
 
-  if (aSizingBox == NS_STYLE_CLIP_SHAPE_SIZING_NOBOX) {
+  if (aSizingBox == StyleClipShapeSizing::NoBox) {
     return valueList.forget();
   }
 
   nsAutoString boxString;
   AppendASCIItoUTF16(
-    nsCSSProps::ValueToKeyword(aSizingBox,
+    nsCSSProps::ValueToKeyword(uint8_t(aSizingBox),
                                nsCSSProps::kClipShapeSizingKTable),
                                boxString);
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetString(boxString);
   valueList->AppendCSSValue(val.forget());
 
   return valueList.forget();
 }
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -638,17 +638,18 @@ private:
   bool GetFrameBorderRectHeight(nscoord& aHeight);
 
   /* Helper functions for computing the filter property style. */
   void SetCssTextToCoord(nsAString& aCssText, const nsStyleCoord& aCoord);
   already_AddRefed<CSSValue> CreatePrimitiveValueForStyleFilter(
     const nsStyleFilter& aStyleFilter);
 
   already_AddRefed<CSSValue> CreatePrimitiveValueForClipPath(
-    const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox);
+    const nsStyleBasicShape* aStyleBasicShape,
+    mozilla::StyleClipShapeSizing aSizingBox);
 
   // Helper function for computing basic shape styles.
   already_AddRefed<CSSValue> CreatePrimitiveValueForBasicShape(
     const nsStyleBasicShape* aStyleBasicShape);
   void BoxValuesToString(nsAString& aString,
                          const nsTArray<nsStyleCoord>& aBoxValues);
   void BasicShapeRadiiToString(nsAString& aCssText,
                                const nsStyleCorners& aCorners);
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -9696,27 +9696,27 @@ nsRuleNode::SetStyleClipPathToCSSValue(n
 {
   MOZ_ASSERT(aValue->GetUnit() == eCSSUnit_Array,
              "expected a basic shape or reference box");
 
   const nsCSSValue::Array* array = aValue->GetArrayValue();
   MOZ_ASSERT(array->Count() == 1 || array->Count() == 2,
              "Expect one or both of a shape function and geometry-box");
 
-  uint8_t sizingBox = NS_STYLE_CLIP_SHAPE_SIZING_NOBOX;
+  StyleClipShapeSizing sizingBox = StyleClipShapeSizing::NoBox;
   RefPtr<nsStyleBasicShape> basicShape;
   for (size_t i = 0; i < array->Count(); ++i) {
     if (array->Item(i).GetUnit() == eCSSUnit_Enumerated) {
       int32_t type = array->Item(i).GetIntValue();
-      if (type > NS_STYLE_CLIP_SHAPE_SIZING_VIEW ||
-          type < NS_STYLE_CLIP_SHAPE_SIZING_NOBOX) {
+      if (type > uint8_t(StyleClipShapeSizing::View) ||
+          type < uint8_t(StyleClipShapeSizing::NoBox)) {
         NS_NOTREACHED("unexpected reference box");
         return;
       }
-      sizingBox = (uint8_t)type;
+      sizingBox = static_cast<StyleClipShapeSizing>(type);
     } else if (array->Item(i).GetUnit() == eCSSUnit_Function) {
       basicShape = GetStyleBasicShapeFromCSSValue(array->Item(i), aStyleContext,
                                                   aPresContext, aConditions);
     } else {
       NS_NOTREACHED("unexpected value");
       return;
     }
   }
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -56,24 +56,26 @@ static inline css::Side operator++(css::
 
 // box-sizing
 enum class StyleBoxSizing : uint8_t {
   Content,
   Border
 };
 
 // clip-path sizing
-#define NS_STYLE_CLIP_SHAPE_SIZING_NOBOX   0
-#define NS_STYLE_CLIP_SHAPE_SIZING_CONTENT 1
-#define NS_STYLE_CLIP_SHAPE_SIZING_PADDING 2
-#define NS_STYLE_CLIP_SHAPE_SIZING_BORDER  3
-#define NS_STYLE_CLIP_SHAPE_SIZING_MARGIN  4
-#define NS_STYLE_CLIP_SHAPE_SIZING_FILL    5
-#define NS_STYLE_CLIP_SHAPE_SIZING_STROKE  6
-#define NS_STYLE_CLIP_SHAPE_SIZING_VIEW    7
+enum class StyleClipShapeSizing : uint8_t {
+    NoBox,
+    Content,
+    Padding,
+    Border,
+    Margin,
+    Fill,
+    Stroke,
+    View,
+};
 
 // Basic Shapes
 #define NS_STYLE_BASIC_SHAPE_POLYGON       0
 #define NS_STYLE_BASIC_SHAPE_CIRCLE        1
 #define NS_STYLE_BASIC_SHAPE_ELLIPSE       2
 #define NS_STYLE_BASIC_SHAPE_INSET         3
 
 // box-shadow
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1002,24 +1002,24 @@ nsStyleBasicShape::GetShapeTypeName() co
 }
 
 // --------------------
 // nsStyleClipPath
 //
 nsStyleClipPath::nsStyleClipPath()
   : mType(NS_STYLE_CLIP_PATH_NONE)
   , mURL(nullptr)
-  , mSizingBox(NS_STYLE_CLIP_SHAPE_SIZING_NOBOX)
+  , mSizingBox(mozilla::StyleClipShapeSizing::NoBox)
 {
 }
 
 nsStyleClipPath::nsStyleClipPath(const nsStyleClipPath& aSource)
   : mType(NS_STYLE_CLIP_PATH_NONE)
   , mURL(nullptr)
-  , mSizingBox(NS_STYLE_CLIP_SHAPE_SIZING_NOBOX)
+  , mSizingBox(mozilla::StyleClipShapeSizing::NoBox)
 {
   if (aSource.mType == NS_STYLE_CLIP_PATH_URL) {
     SetURL(aSource.mURL);
   } else if (aSource.mType == NS_STYLE_CLIP_PATH_SHAPE) {
     SetBasicShape(aSource.mBasicShape, aSource.mSizingBox);
   } else if (aSource.mType == NS_STYLE_CLIP_PATH_BOX) {
     SetSizingBox(aSource.mSizingBox);
   }
@@ -1040,17 +1040,17 @@ nsStyleClipPath::operator=(const nsStyle
   if (aOther.mType == NS_STYLE_CLIP_PATH_URL) {
     SetURL(aOther.mURL);
   } else if (aOther.mType == NS_STYLE_CLIP_PATH_SHAPE) {
     SetBasicShape(aOther.mBasicShape, aOther.mSizingBox);
   } else if (aOther.mType == NS_STYLE_CLIP_PATH_BOX) {
     SetSizingBox(aOther.mSizingBox);
   } else {
     ReleaseRef();
-    mSizingBox = NS_STYLE_CLIP_SHAPE_SIZING_NOBOX;
+    mSizingBox = mozilla::StyleClipShapeSizing::NoBox;
     mType = NS_STYLE_CLIP_PATH_NONE;
   }
   return *this;
 }
 
 bool
 nsStyleClipPath::operator==(const nsStyleClipPath& aOther) const
 {
@@ -1091,28 +1091,29 @@ nsStyleClipPath::SetURL(nsIURI* aURL)
   NS_ASSERTION(aURL, "expected pointer");
   ReleaseRef();
   mURL = aURL;
   mURL->AddRef();
   mType = NS_STYLE_CLIP_PATH_URL;
 }
 
 void
-nsStyleClipPath::SetBasicShape(nsStyleBasicShape* aBasicShape, uint8_t aSizingBox)
+nsStyleClipPath::SetBasicShape(nsStyleBasicShape* aBasicShape,
+                               mozilla::StyleClipShapeSizing aSizingBox)
 {
   NS_ASSERTION(aBasicShape, "expected pointer");
   ReleaseRef();
   mBasicShape = aBasicShape;
   mBasicShape->AddRef();
   mSizingBox = aSizingBox;
   mType = NS_STYLE_CLIP_PATH_SHAPE;
 }
 
 void
-nsStyleClipPath::SetSizingBox(uint8_t aSizingBox)
+nsStyleClipPath::SetSizingBox(mozilla::StyleClipShapeSizing aSizingBox)
 {
   ReleaseRef();
   mSizingBox = aSizingBox;
   mType = NS_STYLE_CLIP_PATH_BOX;
 }
 
 // --------------------
 // nsStyleFilter
@@ -2649,21 +2650,45 @@ nsStyleImageLayers::Layer::operator==(co
 }
 
 nsChangeHint
 nsStyleImageLayers::Layer::CalcDifference(const nsStyleImageLayers::Layer& aNewLayer,
                                           nsChangeHint aPositionChangeHint) const
 {
   nsChangeHint hint = nsChangeHint(0);
   if (!EqualURIs(mSourceURI, aNewLayer.mSourceURI)) {
-    hint |= nsChangeHint_UpdateEffects |
-            nsChangeHint_RepaintFrame;
-    // Mask changes require that we update the PreEffectsBBoxProperty,
-    // which is done during overflow computation.
-    hint |= nsChangeHint_UpdateOverflow;
+    hint |= nsChangeHint_RepaintFrame;
+
+    // If Layer::mSourceURI links to a SVG mask, it has a fragment. Not vice
+    // versa. Here are examples of URI contains a fragment, two of them link
+    // to a SVG mask:
+    //   mask:url(a.svg#maskID); // The fragment of this URI is an ID of a mask
+    //                           // element in a.svg.
+    //   mask:url(#localMaskID); // The fragment of this URI is an ID of a mask
+    //                           // element in local document.
+    //   mask:url(b.svg#viewBoxID); // The fragment of this URI is an ID of a
+    //                              // viewbox defined in b.svg.
+    // That is, if mSourceURI has a fragment, it may link to a SVG mask; If
+    // not, it "must" not link to a SVG mask.
+    bool maybeSVGMask = false;
+    if (mSourceURI) {
+      mSourceURI->GetHasRef(&maybeSVGMask);
+    }
+    if (!maybeSVGMask && aNewLayer.mSourceURI) {
+      aNewLayer.mSourceURI->GetHasRef(&maybeSVGMask);
+    }
+
+    // Return nsChangeHint_UpdateEffects and nsChangeHint_UpdateOverflow if
+    // either URI might link to an SVG mask.
+    if (maybeSVGMask) {
+      hint |= nsChangeHint_UpdateEffects;
+      // Mask changes require that we update the PreEffectsBBoxProperty,
+      // which is done during overflow computation.
+      hint |= nsChangeHint_UpdateOverflow;
+    }
   } else if (mAttachment != aNewLayer.mAttachment ||
              mClip != aNewLayer.mClip ||
              mOrigin != aNewLayer.mOrigin ||
              mRepeat != aNewLayer.mRepeat ||
              mBlendMode != aNewLayer.mBlendMode ||
              mSize != aNewLayer.mSize ||
              mImage != aNewLayer.mImage ||
              mMaskMode != aNewLayer.mMaskMode ||
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -3517,31 +3517,32 @@ struct nsStyleClipPath
   void SetURL(nsIURI* aURL);
 
   nsStyleBasicShape* GetBasicShape() const {
     NS_ASSERTION(mType == NS_STYLE_CLIP_PATH_SHAPE, "wrong clip-path type");
     return mBasicShape;
   }
 
   void SetBasicShape(nsStyleBasicShape* mBasicShape,
-                     uint8_t aSizingBox = NS_STYLE_CLIP_SHAPE_SIZING_NOBOX);
-
-  uint8_t GetSizingBox() const { return mSizingBox; }
-  void SetSizingBox(uint8_t aSizingBox);
+                     mozilla::StyleClipShapeSizing aSizingBox =
+                     mozilla::StyleClipShapeSizing::NoBox);
+
+  mozilla::StyleClipShapeSizing GetSizingBox() const { return mSizingBox; }
+  void SetSizingBox(mozilla::StyleClipShapeSizing aSizingBox);
 
 private:
   void ReleaseRef();
   void* operator new(size_t) = delete;
 
   int32_t mType; // see NS_STYLE_CLIP_PATH_* constants in nsStyleConsts.h
   union {
     nsStyleBasicShape* mBasicShape;
     nsIURI* mURL;
   };
-  uint8_t mSizingBox; // see NS_STYLE_CLIP_SHAPE_SIZING_* constants in nsStyleConsts.h
+  mozilla::StyleClipShapeSizing mSizingBox;
 };
 
 struct nsStyleFilter
 {
   nsStyleFilter();
   nsStyleFilter(const nsStyleFilter& aSource);
   ~nsStyleFilter();
 
--- a/layout/svg/nsCSSClipPathInstance.cpp
+++ b/layout/svg/nsCSSClipPathInstance.cpp
@@ -63,23 +63,23 @@ nsCSSClipPathInstance::HitTestBasicShape
 }
 
 already_AddRefed<Path>
 nsCSSClipPathInstance::CreateClipPath(DrawTarget* aDrawTarget)
 {
   nsRect r;
   // XXXkrit SVG needs to use different boxes.
   switch (mClipPathStyle.GetSizingBox()) {
-    case NS_STYLE_CLIP_SHAPE_SIZING_CONTENT:
+    case StyleClipShapeSizing::Content:
       r = mTargetFrame->GetContentRectRelativeToSelf();
       break;
-    case NS_STYLE_CLIP_SHAPE_SIZING_PADDING:
+    case StyleClipShapeSizing::Padding:
       r = mTargetFrame->GetPaddingRectRelativeToSelf();
       break;
-    case NS_STYLE_CLIP_SHAPE_SIZING_MARGIN:
+    case StyleClipShapeSizing::Margin:
       r = mTargetFrame->GetMarginRectRelativeToSelf();
       break;
     default: // Use the border box
       r = mTargetFrame->GetRectRelativeToSelf();
   }
 
   if (mClipPathStyle.GetType() != NS_STYLE_CLIP_PATH_SHAPE) {
     // TODO Clip to border-radius/reference box if no shape
--- a/toolkit/content/widgets/popup.xml
+++ b/toolkit/content/widgets/popup.xml
@@ -311,45 +311,37 @@
       <handler event="popuphiding"><![CDATA[
         try {
           this._currentFocus = document.commandDispatcher.focusedElement;
         } catch (e) {
           this._currentFocus = document.activeElement;
         }
       ]]></handler>
       <handler event="popuphidden"><![CDATA[
-        function doFocus() {
-          // Focus was set on an element inside this panel,
-          // so we need to move it back to where it was previously
-          try {
-            let fm = Components.classes["@mozilla.org/focus-manager;1"]
-                               .getService(Components.interfaces.nsIFocusManager);
-            fm.setFocus(prevFocus, fm.FLAG_NOSCROLL);
-          } catch(e) {
-            prevFocus.focus();
-          }
-        }
         var currentFocus = this._currentFocus;
         var prevFocus = this._prevFocus ? this._prevFocus.get() : null;
         this._currentFocus = null;
         this._prevFocus = null;
-        if (prevFocus && this.getAttribute("norestorefocus") != "true") {
+        if (prevFocus && currentFocus && this.getAttribute("norestorefocus") != "true") {
           // Try to restore focus
           try {
             if (document.commandDispatcher.focusedWindow != window)
               return; // Focus has already been set to a window outside of this panel
           } catch(ex) {}
-
-          if (!currentFocus) {
-            doFocus();
-            return;
-          }
           while (currentFocus) {
             if (currentFocus == this) {
-              doFocus();
+              // Focus was set on an element inside this panel,
+              // so we need to move it back to where it was previously
+              try {
+                let fm = Components.classes["@mozilla.org/focus-manager;1"]
+                                   .getService(Components.interfaces.nsIFocusManager);
+                fm.setFocus(prevFocus, fm.FLAG_NOSCROLL);
+              } catch(e) {
+                prevFocus.focus();
+              }
               return;
             }
             currentFocus = currentFocus.parentNode;
           }
         }
       ]]></handler>
     </handlers>
   </binding>